JavaRush/Java блог/Random UA/Spring - це не страшно, або як поставити питання БД
Павел
11 рівень

Spring - це не страшно, або як поставити питання БД

Стаття з групи Random UA
учасників
ЗМІСТ ЦИКЛУ СТАТЕЙ Сьогодні ми дорозбираємо роботу з базою в рамках нашого проекту. Якщо ви все робабо правильно, то у вас має бути pom ось із такими залежностями:
<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>
І ось така структура проекту: Spring - це не страшно, або як поставити питання БД - 1 Знаєте, кого ми давно не згадували? Це application.yml, ми поговорабо небагато про нього в одній з минулих статей. А тепер давайте візьмемо та видалимо його! Так, так delete і все! Якщо ми запустимо зараз проект, все буде працювати як і раніше, спробуйте це зробити. Це сталося через те, що Spring сам налаштувався на дефолних налаштуваннях. Тепер треба повернути наш ямл файл назад у папку ресурси, він нам ще знадобиться: application.yml (найменування має бути таким самим)
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
Минулого разу ми за допомогою методів інтерфейсу 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);
}
Якщо ви прочитали про SQL , як я вас просив минулого разу, то ви повинні знати, що такі дії з БД повинні виконуватися за допомогою запитів SQL . Але в проекті на це немає і натяку, навіть у логах консолі немає нічого схожого. Давайте їх знайдемо, відкриваємо application.yml, знаходимо там термін show-sql: (показати sql) і змінюємо false на true. Запускаємо проект і дивимося в консоль, логи наповнабося новими записами дуже схожими на SQL, насправді більшість з них зрозуміти не дивно, наприклад:
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))
Але цей запис може викликати багато запитань через своїх знаків питань:
Hibernate: insert into fruit_table (fruit_name, provider_code, id_fruit) values (?, ?, ?)
Давайте мислити логічно: По-перше ми бачимо слово Hibernate, значить цей потай хлопець приклав тут свою волохату лапу. Прочитавши про нього в інтернеті, ми дізнаємося, що містер Hiber – це реалізація ORM-моделі. Об'єктно-реляційна модель описує відносини між програмними об'єктами та записами у БД. Зафіксували цю думку, продовжуємо мислити логічно: З одного боку, у нас є об'єкт FruitEntity , у нього є три поля: Integer id; String fruitName; Integer providerCode. З іншого боку, ми маємо таблицю в БД fruit_table з полями id_fruit тип integer, fruit_name тип varchar(255) , provider_code типinteger. Грубо кажучи, Hibernate бере об'єкт FruitEntity , витягує значення полів об'єкта і записує їх у відповідні поля таблиці. У мене до вас питання: Дивіться, в класі InitiateUtils ми реалізували заповнення таблиці фруктів, але чому ми тут задали значення тільки двом полям, де третє?
new FruitEntity()
        .setFruitName("Fruit1")//раз
        .setProviderCode(Math.abs(new Random().nextInt() % 10)),//два
                                            //три???
Впевнений ви розберетеся в цьому самі, до того ж ми миттю торкалися цього питання позаминулої статті. Для початку розберіться якого поля тут немає, а далі ви все зрозумієте. Ну що ж, Hiber молодець, нагенерував за нас купу запитів. Але і ми не ликом шиті, давайте в класі FruitService реалізуємо ще кілька методів з інтерфейсу JpaRepository<>
//возвращает запись из таблицы по id
public Optional<FruitEntity> getById(Integer id){
   return fruitRepository.findById(id);
}

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

//возвращает true або false при поиске в таблице Фруктов об'єкта который соответствует типу FruitEntity або принадлежит к типу об'єкта который наследуется от FruitEntity
public Boolean exist(Example<? extends FruitEntity> example){
    return fruitRepository.exists(example);
}
Реалізуйте такі самі методи у класі ProviderService. Потім використовуйте їх у класі InitiateUtils для FruitEntity та ProviderEntity , результат виведете в консоль. (До речі, якщо ви не знали швидко написати “System.out.println()” можна якщо набрати sout і натиснути ентер, таже штука працює з “public static void main(String[] args){}” достатньо набрати psvm ну і так далі ). Я думаю, ви вже впоралися і ми готові йти далі. Давайте зайдемо в інтерфейс FruitRepository і почнемо в ньому набирати (саме набирати, а не копіювати) наступний метод: List<FruitEntity> f Повинна вийти наступна штука Spring - це не страшно, або як поставити питання БД - 2 Просто називаєте метод як складаєте запит: findById(Integer id) - знайде об'єкт по id; countFruitEntityByFruitName(String name) - порахує кількість фруктів із певним ім'ям; Це запити, що генеруються на ім'я методу, обов'язково почитайте про них і реалізуйте в класі FruitService метод between(Integer from, Integer to) для пошуку List<FruitEntity> за значеннями поля provider_codeщо входять у певний інтервал, результат роботи виведете в консоль. Наприклад: знайти всі фрукти, у яких номер постачальника знаходиться між 5 і 7. Не поспішайте читати далі, доки не реалізуєте метод, це не довго. Як ви могли прочитати у статті про запити на ім'я методу: «Усі запити так не напишеш, але прості можна.» Для більш складних запитів використовується анотація @Query і замість SQL тут використовується JPQL (теж візьміть на замітку цю статтю), для нашого проекту можна зробити JOIN запити так:
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();

}
Стандартний SQL запит був би таким: "select fruit_table.fruit_name, provider_table.provider_name з fruit_table left join provider_table on fruit_table.provider_code = provider_table.id". Тут легко можна встановити відповідність: f ruit_table це FruitEntiy f, де FruitEntiy це тип змінної, f це її найменування, тобто SQL працює з таблицями та полями, а JPQL з об'єктами та їх полями. Знову ж таки fruit_table.fruit_name це f.fruitName ; Так як ми працюємо з об'єктами, то можемо і об'єкт вивести: Напишемо ще один метод FruitRepository
@Query("select f from  FruitEntity f  join ProviderEntity p on f.providerCode = p.id")
List<FruitEntity> joinFruit();
Реалізуємо обидва методи у класі FruitService
public List<String> joinString(){
   return fruitRepository.joinSting();
}

public List<FruitEntity> joinFruit(){
    return fruitRepository.joinFruit();
}
Звучить непогано, але все одно для складних запитів використовують старий добрий SQL
@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",  //по идее эту портянку надо засунуть в якой нибудь  Enum
        nativeQuery = true) //нужно только пометить только nativeQuery = true
ListList<String> joinSqlFruit();
І використовуємо їх усіх у класі 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);
        }
Запускаємо проект і бачимо в консолі нові логи: Таблиця фруктів і їх постачальників 2, fruitName=Fruit2, providerCode=5) FruitEntity(id=3, fruitName=Fruit3, providerCode=2) FruitEntity(id=4, fruitName=Fruit4, providerCode=5) Таблиця фруктів та їх постачальників Fruit2,Provider4 Fruit ,Provider5 Так, якщо вам вже набридли "псевдо" і просто SQL запити в консолі, можете в ямл файлі повернути false на місце. Чому в першій таблиці є null, це ви дізнаєтеся, якщо почитаєте про JOIN SQL. І так, із запитами до БД ми закінчабо, я впевнений, що у вас залишилося багато питань, але я сподіваюся, що ви шукатимете на них відповіді, шляхи пошуку я спробував підсвітити. Давайте спробуємо з резюмувати все, що ми дізналися за цей час: 1. Можна запустити веб-сервер на Spring і це не складно. 2. Для розуміння як це все працює необхідно поринути в теорію. 3. А щоб розуміння перейшло у фізичний код треба кодити, і перш ніж йти далі, набийте руку на простих проектах на spring - boot . І краще не копіювати написаний код, а переписувати його. Я викладу проект, який ми з вами паболи сюди, але сподіватимусь на вашу свідомість і впевнений ви не бездумно копіпаститимете. Посилання на репозиторій git clone https://FromJava@bitbucket.org/FromJava/jd.git Для тих хто не знає як користуватися цим посиланням Рекомендую реалізувати два тренувальні проекти: Проект про фарбування машин: Перший клас: CarEntity{ Integer id; String modelName; String color; } Другий клас: ColorEntity { Integer id; String color; Integer price; } Наповніть базу (придумайте реалістичні назви так буде легше для розуміння), реалізуйте: , entity, repositories, services, створіть стандартні та міжтабличні запити (Скільки коштує фарбування BMW у червоний колір? Який колір найдорожчий? тощо); Проект про бібліотеку: Перший клас: BookEntity{ Integer id; String nameBook; Integer yearCreat; Integer autorId; } Другий клас: AutorEntity { Integer id; String firstNameAutor; String lastNameAutor; } Наповніть базу (придумайте реалістичні назви так буде легше для розуміння), реалізуйте: entity, repositories, services, створіть стандартні та міжтабличні запити (Хто написав яку книгу? Яка книга написана раніше за всіх? Які книги були написані з 1800 по 1900? Хто з авторів написав найбільше книг?); Приклади для заповнення бази проекту "Бібліотека" Таблиця книг BookEntity(id=1, nameBook=Горе від розуму, yearCreat=1824, authorId=1) BookEntity(id=2, nameBook=Війна та мир, yearCreat=1863, authorId=2) BookEntity(id=3, nameBook= Мцирі, yearCreat=1838, authorId=3) BookEntity(id=4, nameBook=Євгеній Онєгін, yearCreat=1833, authorId=4) Таблиця авторів AuthorEntity(id=1, firstNameAuthor=Александр, lastNameAuthor= , firstNameAuthor=Лев, lastNameAuthor=Толстой) AuthorEntity(id=3, firstNameAuthor=Михайло, lastNameAuthor=Лермонтів) AuthorEntity(id=4, firstNameAuthor=Олександр, lastNameAuthor=Пушкін) Всім удачі !
Коментарі
  • популярні
  • нові
  • старі
Щоб залишити коментар, потрібно ввійти в систему
Для цієї сторінки немає коментарів.