JavaRush /בלוג Java /Random-HE /Spring — это не страшно, или как задать вопрос БД
Павел
רָמָה

Spring — это не страшно, или как задать вопрос БД

פורסם בקבוצה
СОДЕРЖАНИЕ ЦИКЛА СТАТЕЙ Сегодня мы доразбираем работу с базой в рамках нашего проекта. Если вы все делали правильно, то у вас должен быть 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 — это не страшно, or How задать вопрос БД - 1 Знаете кого мы давно не вспоминали? Это application.yml, мы поговорor не много о нем в одной из прошлых статей. А теперь давайте возьмем и удалим его! Да, да delete и все! Если мы запустим сейчас проект, то все будет работать How и раньше, попробуйте это сделать. Это произошло по тому, что 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<> реализовали несколько requestов к базе:

//сохранить одну запись в таблицу фруктов
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, How я вас просил в прошлый раз, то вы должны знать, что такие действия с БД должны выполняться с помощью requestов SQL . Но в проекте на это нет и намека, даже в логах консоли нет ни чего похожего. Давайте их найдем, открываем application.yml, находим там срочку show-sql: (показать sql) и меняем false на true. Запускаем проект и смотрим в консоль, логи наполнorсь новыми записями очень похожими на 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-модели. Объектно-реляционная модель описывает отношения между программными an objectми и записями в БД. Зафиксировали эту мысль, продолжаем мыслить логически: С одной стороны, у нас есть an object FruitEntity у него есть три поля: Integer id; String fruitName; Integer providerCode. С другой стороны, у нас есть table в БД fruit_table с полями id_fruit тип integer, fruit_name тип varchar(255), provider_code тип integer. Грубо говоря Hibernate берет an object FruitEntity, вытаскивает значения полей an object и записывает их в соответствующие поля таблицы. У меня к вам вопрос: Смотрите, в классе InitiateUtils мы реализовали заполнение таблицы фруктов, но почему то мы тут задали meaning только двум полям, где третье?

new FruitEntity()
        .setFruitName("Fruit1")//раз
        .setProviderCode(Math.abs(new Random().nextInt() % 10)),//два
                                            //три???
Уверен вы разберетесь в этом сами, к тому же мы мельком касались этого вопроса в позапрошлой статье. Для начала разберитесь Howого поля тут нет, а дальше вы все поймете. Ну что ж, Hiber молодец, нагенерировал за нас кучу requestов. Но и мы не лыком шиты, давайте в классе FruitService реализуем еще несколько методов из интерфейса JpaRepository<>

//возвращает запись из таблицы по id
public Optional<FruitEntity> getById(Integer id){
   return fruitRepository.findById(id);
}

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

//возвращает true or false при поиске в таблице Фруктов an object который соответствует типу FruitEntity or принадлежит к типу an object который наследуется от 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 ну и так далее). Я думаю вы уже справorсь и мы готовы идти дальше. Давайте зайдем в интерфейс FruitRepository и начнем в нем набирать (именно набирать а не копировать) следующий метод: List<FruitEntity> f Должна получиться следующая штука Spring — это не страшно, or How задать вопрос БД - 2 Просто называете метод How будто составляете request: findById(Integer id) - найдет an object по id; countFruitEntityByFruitName(String name) - посчитает количество фруктов с определенным именем; Это requestы, генерируемые по имени метода обязательно почитайте про них и реализуйте в классе FruitService метод between(Integer from, Integer to) для поиска List<FruitEntity> по значениям поля provider_code входящим в определенный интервал, результат работы выведете в консоль. Например: найти все фрукты, у которых номер поставщика находиться между 5 и 7. Не торопитесь читать дальше, пока не реализуете метод, это не долго. Как вы могли прочитать в статье про requestы по имени метода: «Все requestы так не напишешь, но простые можно.» Для более сложных requestов используется annotation @Query и instead of SQL здесь используется JPQL(тоже возмите на заметку эту статью), для нашего проекта можно сделать JOIN requestы, так:

 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 request был бы таким: "select fruit_table.fruit_name, provider_table.provider_name from fruit_table left join provider_table on fruit_table.provider_сode = provider_table.id". Здесь легко можно установить соответствие: fruit_table это FruitEntiy f, где FruitEntiy это тип переменной, f это ее наименование, то есть SQL работает с tableми и полями, а JPQL с an objectми и их полями. Опять же fruit_table.fruit_name это f.fruitName; Так How мы работаем с an objectми то можем и an object вывести: Напишем еще один метод 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();
}
Звучит не плохо, но все равно для сложных requestов используют старый добрый 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",  //по идее эту портянку надо засунуть в Howой нибудь  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);
        }
Запускаем проект и видим в консоли новые логи: Таблица фруктов и их поставщиков Fruit1,null Fruit2,Provider5 Fruit3,Provider2 Fruit4,Provider5 Fruit5,null Fruit6,null Fruit7,null Fruit8,null Fruit9,null Таблица фруктов и их поставщиков FruitEntity(id=2, fruitName=Fruit2, providerCode=5) FruitEntity(id=3, fruitName=Fruit3, providerCode=2) FruitEntity(id=4, fruitName=Fruit4, providerCode=5) Таблица фруктов и их поставщиков Fruit2,Provider5 Fruit3,Provider2 Fruit4,Provider5 Да, если вам уже надоели "псевдо" и просто SQL requestы в консоли, можете в ямл файле вернуть false на место. Почему в первой таблице есть null, это вы узнаете если почитаете про JOIN SQL . И так, с requestами к БД мы закончor, я уверен, что у вас осталось много вопросов, но я надеюсь, что вы будете искать на них ответы, пути поиска я попытался подсветить. Давайте попытаемся с резюмировать все что мы узнали за это время: 1. Можно запустить web server на Spring и это не сложно. 2. Для понимания How это все работает необходимо погрузиться в теорию. Про книгу Статья про спринг Статья про полезные вещи 3. А что бы понимание перешло в физический code надо codeить, и прежде чем идти дальше, набейте руку на простых проектах на spring-boot. И лучше не копировать написанный code, а переписывать его. Я выложу проект, который мы с вами пorли сюда, но буду надеяться на вашу сознательность и уверен вы не будете бездумно копипастить. Ссылка на репозиторий git clone https://FromJava@bitbucket.org/FromJava/jd.git Для тех кто не знает How пользоваться этой ссылкой Рекомендую реализовать два тренировочных проекта: Проект про покраску машин: Первый класс: CarEntity{ Integer id; String modelName; String color; } Второй класс: ColorEntity{ Integer id; String color; Integer price; } Наполните базу (придумайте реалистичные названия так будет легче для понимания), реализуйте: , entity, repositories, services, создайте стандартные и межтабличные requestы (Сколько стоит покраска BMW в красный цвет? Какой цвет самый дорогой? Напишите модели в консоль в алфавитном порядке и т.д.); Проект про библиотеку: Первый класс: BookEntity{ Integer id; String nameBook; Integer yearCreat; Integer autorId; } Второй класс: AutorEntity{ Integer id; String firstNameAutor; String lastNameAutor; } Наполните базу (придумайте реалистичные названия так будет легче для понимания), реализуйте: entity, repositories, services, создайте стандартные и межтабличные requestы (Кто написал Howую книгу? Какая книга написана раньше всех? Какие книги были написаны с 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=Грибоедов) AuthorEntity(id=2, firstNameAuthor=Лев, lastNameAuthor=Толстой) AuthorEntity(id=3, firstNameAuthor=Михаил, lastNameAuthor=Лермонтов) AuthorEntity(id=4, firstNameAuthor=Александр, lastNameAuthor=Пушкин) Всем удачи, еще увидимся!
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION