JavaRush /Blog Java /Random-PL /Wiosna nie jest straszna, czyli jak zadać pytanie do bazy...
Павел
Poziom 11

Wiosna nie jest straszna, czyli jak zadać pytanie do bazy danych

Opublikowano w grupie Random-PL
ZAWARTOŚĆ CYKLU ARTYKUŁÓW Dziś finalizujemy prace z bazą danych w ramach naszego projektu. Jeśli wszystko zrobiłeś poprawnie, powinieneś mieć pom z następującymi zależnościami:
<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <java.version>1.8</java.version>
</properties>
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.0.RELEASE</version>
    <relativePath/><!-- lookup parent from repository -->
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>
A oto struktura projektu: Wiosna nie jest straszna, czyli jak zadać pytanie do bazy danych - 1 Czy wiecie, o kim długo nie pamiętaliśmy? To jest plik application.yml, nie mówiliśmy o nim zbyt wiele w jednym z poprzednich artykułów. Teraz przejdźmy dalej i usuń to! Tak, tak, usuń i to wszystko! Jeśli teraz uruchomimy projekt, wszystko będzie działać jak poprzednio, spróbuj tego. Stało się tak, ponieważ sama Spring została skonfigurowana z ustawieniami domyślnymi. Teraz musimy zwrócić nasz plik yml z powrotem do folderu Resources, nadal będziemy go potrzebować: application.yml (nazwa powinna być taka sama)
spring:
  datasource:
    driverClassName: org.h2.Driver
    url: jdbc:h2:mem:test;
    username: sa
    password:
    h2:
      console:
        enabled: true
  jpa:
    hibernate.ddl-auto: create
    generate-ddl: true
    show-sql: false
    properties:
      hibernate:
        dialect: org.hibernate.dialect.H2Dialect
Ostatnim razem zaimplementowaliśmy kilka zapytań do bazy danych wykorzystując metody interfejsu JpaRepository<>:
//сохранить одну запись в таблицу фруктов
public void save(FruitEntity fruitEntity){
    fruitRepository.save(fruitEntity);
}
//получить все записи из таблицы фруктов
public List<FruitEntity> getAll(){
   return fruitRepository.findAll();
}
//сохранить несколько записей в таблицу фруктов
public void saveAll(List<FruitEntity> fruits){
    fruitRepository.saveAll(fruits);
}
Jeśli czytasz o SQL , o co Cię ostatnio prosiłem, to powinieneś wiedzieć, że takie działania z bazą danych muszą być wykonywane przy użyciu zapytań SQL. Ale w projekcie nie ma o tym śladu, nawet w logach konsoli nie ma nic podobnego. Znajdźmy je, otwórz plik application.yml, znajdź tam linię show-sql: (pokaż sql) i zmień wartość false na true. Uruchamiamy projekt i patrzymy na konsolę, logi zapełniają się nowymi wpisami bardzo podobnymi do SQL, tak naprawdę większość z nich nie jest trudna do zrozumienia, na przykład:
Hibernate: drop table fruit_table if exists //удалить таблицу fruit_table  если она есть
Hibernate: drop table provider_table if exists
Hibernate: create table fruit_table (id_fruit integer not null, fruit_name varchar(255), provider_code integer, primary key (id_fruit))//создать таблицу fruit_table с полями id_fruit тип integer not null, fruit_name  тип varchar(255), provider_code тип integer, назначить первичным ключем поле id_fruit
Hibernate: create table provider_table (id_provider integer not null, provider_name varchar(255), primary key (id_provider))
Ale ten wpis może budzić wiele pytań ze względu na znaki zapytania:
Hibernate: insert into fruit_table (fruit_name, provider_code, id_fruit) values (?, ?, ?)
Pomyślmy logicznie: po pierwsze, widzimy słowo Hibernacja, co oznacza, że ​​ten tajemniczy facet położył tu swoją futrzaną łapę. Po przeczytaniu o nim w Internecie dowiadujemy się, że pan Hiber jest implementacją modelu ORM. Model obiektowo-relacyjny opisuje relacje pomiędzy obiektami oprogramowania a rekordami w bazie danych. Po naprawieniu tego pomysłu nadal myślimy logicznie: z jednej strony mamy obiekt FruitEntity , który ma trzy pola: Integer id; String nazwa owocu; Kod dostawcy będący liczbą całkowitą. Z drugiej strony mamy w bazie danych tabelę_owoców z polami id_owoc typu integer, nazwa_owocu typu varchar(255) , kod_dostawcy typu integer. Z grubsza mówiąc, Hibernate pobiera obiekt FruitEntity , wyciąga wartości pól obiektu i zapisuje je w odpowiednich polach tabeli. Mam do Ciebie pytanie: Słuchaj, w klasie InitiateUtils zaimplementowaliśmy wypełnianie tabeli owoców, ale z jakiegoś powodu ustawiliśmy wartość tylko na dwa pola, gdzie jest trzecie?
new FruitEntity()
        .setFruitName("Fruit1")//раз
        .setProviderCode(Math.abs(new Random().nextInt() % 10)),//два
                                            //три???
Jestem pewien, że sam się o tym przekonasz, poza tym pokrótce poruszyliśmy tę kwestię w przedostatnim artykule. Najpierw dowiedz się, którego pola tu nie ma, a wtedy wszystko zrozumiesz. Dobra robota, Hiber wygenerował dla nas kilka próśb. Ale nie jesteśmy ślepi, zaimplementujmy jeszcze kilka metod z interfejsu JpaRepository<> w klasie FruitService
//возвращает запись из таблицы по id
public Optional<FruitEntity> getById(Integer id){
   return fruitRepository.findById(id);
}

//удаляет запись из таблицы по id
public void delById(Integer id){
    fruitRepository.deleteById(id);
}

//возвращает true Lub false при поиске в таблице Фруктов obiektа который соответствует типу FruitEntity Lub принадлежит к типу obiektа который наследуется от FruitEntity
public Boolean exist(Example<? extends FruitEntity> example){
    return fruitRepository.exists(example);
}
Zaimplementuj te same metody w klasie ProviderService. Następnie użyj ich w klasie InitiateUtils dla FruitEntity i ProviderEntity i wypisz wynik na konsoli. (Nawiasem mówiąc, jeśli nie wiesz, możesz szybko napisać „System.out.println()”, wpisując sout i naciskając klawisz Enter. To samo działa z „public static void main(String[] args){} ” po prostu wpisz psvm i gotowe itp. ). Myślę, że już sobie z tym poradziłeś i możemy działać dalej. Przejdźmy do interfejsu FruitRepository i zacznijmy w nim wpisywać (czyli wpisywać, a nie kopiować) następującą metodę: List<FruitEntity> f Powinniśmy otrzymać coś takiego, Wiosna nie jest straszna, czyli jak zadać pytanie do bazy danych - 2 wystarczy wywołać metodę tak jakbyśmy tworzyli zapytanie: findById(Integer id ) - znajduje obiekt po id; countFruitEntityByFruitName(String name) - zliczy ilość owoców o określonej nazwie; Są to zapytania generowane przez nazwę metody; koniecznie o nich poczytaj i zaimplementuj metodę pomiędzy (Integer from, Integer to) w klasie FruitService , aby przeszukać List<FruitEntity> po wartościach pola Provider_code zawartego w określonym odstępie czasu i wyświetlić wynik pracy w konsoli. Na przykład: znajdź wszystkie owoce, których numer dostawcy mieści się w przedziale od 5 do 7. Nie spiesz się z czytaniem dalej, dopóki nie zastosujesz metody, to nie zajmie dużo czasu. Jak mogłeś przeczytać w artykule o zapytaniach według nazwy metody: „Nie możesz pisać wszystkich zapytań w ten sposób, ale można pisać proste”. W przypadku bardziej złożonych zapytań używana jest adnotacja @Query, a zamiast SQL używany jest JPQL (zwróć także uwagę na ten artykuł).W naszym projekcie możesz tworzyć zapytania JOIN w następujący sposób:
package ru.java.rush.repositories;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import ru.java.rush.entities.FruitEntity;

import java.util.List;

@Repository
public interface FruitRepository extends JpaRepository<FruitEntity,Integer> {

    @Query("select f.fruitName, p.providerName from  FruitEntity f left join ProviderEntity p on f.providerCode = p.id")
    List<String> joinSting();

}
Standardowe zapytanie SQL wyglądałoby następująco: „wybierz tabela_owoców.nazwa_owoców, tabela_dostawcy.nazwa_dostawcy z tabeli_owocowej, lewe dołącz do tabeli_dostawcy na tabeli_owocowej.kod_dostawcy = tabela_dostawcy.id”. Tutaj możesz łatwo ustalić powiązanie: f ruit_table to FruitEntiy f, gdzie FruitEntiy to typ zmiennej, f to jej nazwa, czyli SQL działa z tabelami i polami, a JPQL z obiektami i ich polami. Ponownie tabela_owoców.nazwa_owocu to f.Nazwa_owocu ; Ponieważ pracujemy z obiektami, możemy wyprowadzić obiekt: Napiszmy kolejną metodę FruitRepository
@Query("select f from  FruitEntity f  join ProviderEntity p on f.providerCode = p.id")
List<FruitEntity> joinFruit();
Zaimplementujmy obie metody w klasie FruitService
public List<String> joinString(){
   return fruitRepository.joinSting();
}

public List<FruitEntity> joinFruit(){
    return fruitRepository.joinFruit();
}
Nie brzmi to źle, ale nadal używają starego, dobrego SQL do złożonych zapytań
@Query(
        value = "select fruit_table.fruit_name, provider_table.provider_name from  fruit_table  join provider_table on fruit_table.provider_code = provider_table.id_provider",  //по идее эту портянку надо засунуть в Jakой нибудь  Enum
        nativeQuery = true) //нужно только пометить только nativeQuery = true
ListList<String> joinSqlFruit();
I używamy ich wszystkich w klasie InitiateUtils
System.out.println("\nТаблица фруктов и их поставщиков");
for (String join : fruitService.joinString()) {
    System.out.println(join);
}

System.out.println("\nТаблица фруктов и их поставщиков");
for (FruitEntity join : fruitService.joinFruit()) {
    System.out.println(join);
}

System.out.println("\nТаблица фруктов и их поставщиков");
        for (String join : fruitService.joinSqlFruit()) {
            System.out.println(join);
        }
Uruchamiamy projekt i w konsoli widzimy nowe logi: Tabela owoców i ich dostawców Fruit1,null Fruit2,Provider5 Fruit3,Provider2 Fruit4,Provider5 Fruit5,null Fruit6,null Fruit7,null Fruit8,null Fruit9,null Tabela owoców i ich dostawcy FruitEntity(id= 2, FruitName=Fruit2, dostawcaCode=5) FruitEntity(id=3, FruitName=Fruit3, dostawcaCode=2) FruitEntity(id=4, FruitName=Fruit4, dostawcaCode=5) Tabela owoców i ich dostawców Fruit2 ,Provider5 Fruit3,Provider2 Fruit4 ,Provider5 Tak, jeśli masz już dość „pseudo” i samych zapytań SQL w konsoli, możesz zwrócić w jego miejscu wartość false w pliku yaml. Dlaczego w pierwszej tabeli jest null, dowiesz się czytając o JOIN SQL . I tak zapytania do bazy danych mamy już za sobą, na pewno macie jeszcze wiele pytań, ale mam nadzieję, że będziecie na nie szukać odpowiedzi, starałem się podkreślić ścieżki poszukiwań. Spróbujmy podsumować wszystko, czego nauczyliśmy się w tym czasie: 1. Serwer WWW można uruchomić wiosną i nie jest to trudne. 2. Aby zrozumieć, jak to wszystko działa, musisz zgłębić teorię. O książce Artykuł o wiośnie Artykuł o przydatnych rzeczach 3. Aby zrozumienie przerodziło się w fizyczny kod, musisz zakodować, a zanim przejdziesz dalej, zdobyć proste projekty na spring-boocie. I lepiej nie kopiować napisanego kodu, ale napisać go od nowa. Opublikuję tutaj projekt, nad którym wspólnie pracowaliśmy, ale liczę na Waszą świadomość i jestem pewien, że nie będziecie bezmyślnie kopiować-wklejać. Link do repozytorium klonów git https://FromJava@bitbucket.org/FromJava/jd.git Dla tych, którzy nie wiedzą jak skorzystać z tego linku polecam realizację dwóch projektów szkoleniowych: Projekt dotyczący malowania samochodów: First class: CarEntity{ Integer ID; Nazwa modelu ciągu; Kolor sznurka; } Druga klasa: ColorEntity{ Identyfikator całkowity; Kolor sznurka; Cena całkowita; } Wypełnij bazę danych (wymyśl realistyczne nazwy, żeby było łatwiej zrozumieć), zaimplementuj: , encje, repozytoria, usługi, twórz zapytania standardowe i międzytabelowe (Ile kosztuje pomalowanie BMW na czerwono? Jaki jest kolor najdroższy? Zapisuj modele do konsoli w kolejności alfabetycznej itp.); Projekt biblioteczny: Pierwsza klasa: BookEntity{ Identyfikator całkowity; Nazwa ciąguKsiążka; Rok całkowityCreat; Liczba całkowita autorId; } Druga klasa: AutorEntity{ Identyfikator całkowity; String imięNazwaAutor; Ciąg nazwiskoAutor; } Wypełnij bazę danych (wymyśl realistyczne nazwy, żeby było łatwiej zrozumieć), zaimplementuj: encje, repozytoria, usługi, stwórz zapytania standardowe i międzytabelowe (Kto napisał jaką książkę? Która książka została napisana pierwsza? Które książki zostały napisane od 1800 do 1900? Który z autorów napisał najwięcej książek?); Przykłady wypełnienia bazy projektów „Biblioteka”. Tabela książek BookEntity(id=1, nameBook=Biada Wita, rokCreat=1824, autorId=1) BookEntity(id=2, nameBook=Wojna i pokój, rokCreat=1863, autorId=2) BookEntity(id=3, nameBook= Mtsyri, yearCreat=1838,authorId=3) BookEntity(id=4, nameBook=Eugeniusz Oniegin, yearCreat=1833, autorId=4) Tabela autorów AuthorEntity(id=1, FirstNameAuthor=Aleksander, lastNameAuthor=Gribojedow) AuthorEntity(id=2 , imię_Author=Lew, nazwiskoAuthor=Tołstoj) AuthorEntity(id=3, imię_Author=Michaił, nazwiskoAuthor=Lermontow) AuthorEntity(id=4, imię_Author=Aleksander, nazwiskoAuthor=Puszkin) Powodzenia wszystkim, do zobaczenia ponownie!
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION