JavaRush /Java Blog /Random-KO /봄은 무섭지 않다, 혹은 데이터베이스에 질문하는 방법
Павел
레벨 11

봄은 무섭지 않다, 혹은 데이터베이스에 질문하는 방법

Random-KO 그룹에 게시되었습니다
기사 주기의 내용 오늘 우리는 프로젝트의 일부로 데이터베이스 작업을 마무리하고 있습니다. 모든 작업을 올바르게 수행했다면 다음 종속성을 가진 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>
그리고 프로젝트의 구조는 다음과 같습니다. 봄은 무섭지 않다, 데이터베이스에 질문하는 방법 - 1 우리가 오랫동안 기억하지 못한 사람이 누구인지 아시나요? 이것은 application.yml입니다. 이전 기사에서는 이에 대해 많이 언급하지 않았습니다. 이제 삭제해 보겠습니다. 예, 예, 삭제하면 끝입니다! 지금 프로젝트를 시작하면 모든 것이 이전처럼 작동할 것입니다. 이것을 시도해 보세요. 이는 Spring 자체가 기본 설정으로 구성되었기 때문에 발생했습니다. 이제 yml 파일을 다시 resources 폴더로 반환해야 합니다. 여전히 필요합니다: 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: 줄을 찾아(show 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 (?, ?, ?)
논리적으로 생각해 봅시다. 첫째, 최대 절전 모드라는 단어가 있습니다. 이는 이 비밀스러운 사람이 털복숭이 앞발을 여기에 뒀다는 의미입니다. 인터넷에서 그에 대해 읽은 후 우리는 Mr. Hiber가 ORM 모델을 구현했다는 것을 알게 됩니다. 객체-관계형 모델은 데이터베이스의 소프트웨어 객체와 레코드 간의 관계를 설명합니다. 이 아이디어를 수정한 후 우리는 계속해서 논리적으로 생각합니다. 한편으로는 FruitEntity 개체가 있고 여기에는 세 가지 필드가 있습니다. Integer id; 문자열 과일이름; 정수 공급자 코드입니다. 반면, 데이터베이스 Fruit_table 에는 id_fruit 유형 정수, Fruit_name 유형 varchar(255) , 공급자_코드 유형 정수 필드가 있는 테이블이 있습니다 . 대략적으로 말하자면, 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 or false при поиске в таблице Фруктов an object который соответствует типу FruitEntity or принадлежит к типу an object который наследуется от FruitEntity
public Boolean exist(Example<? extends FruitEntity> example){
    return fruitRepository.exists(example);
}
ProviderService 클래스에서 동일한 메서드를 구현합니다. 그런 다음 FruitEntityProviderEntity 에 대한 InitiateUtils 클래스 에서 이를 사용 하고 결과를 콘솔에 인쇄합니다. (그런데, 몰랐다면 sout을 입력하고 Enter를 눌러 "System.out.println()"을 빠르게 작성할 수 있습니다. "public static void main(String[] args){}에서도 같은 작업이 작동합니다. ” 그냥 psvm을 입력하면 됩니다. ). 나는 당신이 이미 그 문제를 처리했고 우리는 다음 단계로 나아갈 준비가 되어 있다고 생각합니다. FruitRepository 인터페이스 로 가서 다음 메소드를 입력하기 시작합니다(즉, 복사하지 않고 입력): List<FruitEntity> f 다음 항목을 얻어야 합니다. 쿼리를 작성하는 것처럼 메소드를 호출하면 됩니다. findById(Integer id ) - ID로 객체를 찾습니다. countFruitEntityByFruitName(String name) - 특정 이름을 가진 과일의 수를 계산합니다. 메소드 이름으로 생성되는 쿼리 이므로 반드시 읽어보시고 FruitService 클래스에 between(Integer from, Integer to) 메소드를 구현하여 List<FruitEntity> 에 포함된 공급자 _코드 필드 의 값으로 검색하시기 바랍니다. 일정 간격으로 작업 결과를 콘솔에 표시합니다. 예를 들어 공급자 번호가 5에서 7 사이인 모든 과일을 찾으세요. 메서드를 구현할 때까지 서두르지 마세요. 시간이 오래 걸리지 않습니다. 메소드 이름별 쿼리에 대한 기사에서 읽었을 수도 있습니다. "이와 같은 모든 쿼리를 작성할 수는 없지만 간단한 쿼리는 작성할 수 있습니다." 더 복잡한 쿼리의 경우 @Query 주석이 사용되고 SQL 대신 JPQL이 사용됩니다 .(이 기사도 참고하세요.) 우리 프로젝트의 경우 다음과 같이 JOIN 쿼리를 만들 수 있습니다. 봄은 무섭지 않다, 데이터베이스에 질문하는 방법 - 2
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 쿼리는 다음과 같습니다. "fruit_table에서fruit_table.fruit_name, 공급자_테이블.provider_name을 선택하고fruit_table.provider_code = 공급자_테이블.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",  //по идее эту портянку надо засунуть в 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, 공급자코드=5) FruitEntity(id=3, FruitName=Fruit3, 공급자코드=2) FruitEntity(id=4, FruitName=Fruit4, 공급자코드=5) 과일 및 공급자 표 Fruit2 ,Provider5 Fruit3,Provider2 Fruit4 ,Provider5 예, 이미 "의사" 및 콘솔의 SQL 쿼리에 지쳤다면 yaml 파일의 해당 위치에서 false를 반환할 수 있습니다. 첫 번째 테이블에 null이 있는 이유는 JOIN SQL을 읽어보면 알 수 있습니다 . 그래서 우리는 데이터베이스에 대한 쿼리를 마쳤습니다. 여전히 질문이 많을 것이라고 확신하지만 이에 대한 답변을 찾으시기를 바랍니다. 검색 경로를 강조하려고 노력했습니다. 이번 시간 동안 배운 모든 내용을 요약해 보겠습니다. 1. Spring에서 웹 서버를 실행할 수 있으며 어렵지 않습니다. 2. 모든 것이 어떻게 작동하는지 이해하려면 이론에 뛰어들 필요가 있습니다. 책 소개 spring 관련 기사 유용한 것들에 대한 기사 3. 물리적 코드로 변환하는 것을 이해하려면 코딩을 해야 하며, 계속 진행하기 전에 spring-boot에 대한 간단한 프로젝트를 손에 넣어야 합니다. 그리고 작성된 코드를 복사하는 것이 아니라 다시 작성하는 것이 좋습니다. 나는 당신과 내가 작업해온 프로젝트를 여기에 게시할 것입니다. 그러나 나는 당신의 인식에 의존할 것이며 당신이 무심코 복사하여 붙여넣지 않을 것이라고 확신합니다. git clone 저장소 링크 https://FromJava@bitbucket.org/FromJava/jd.git 이 링크를 사용하는 방법을 모르는 사람들을 위해 두 가지 교육 프로젝트를 구현하는 것이 좋습니다. 자동차 페인팅에 관한 프로젝트: 첫 번째 클래스: CarEntity{ Integer ID; 문자열 모델명; 문자열 색상; } 두 번째 클래스: ColorEntity{ Integer id; 문자열 색상; 정수 가격; } 데이터베이스를 채우고(이해하기 쉽도록 현실적인 이름을 정함), 구현: , 엔터티, 저장소, 서비스, 표준 및 교차 테이블 쿼리 생성(BMW 빨간색을 칠하는 데 비용이 얼마나 드나요? 색상은 무엇입니까?) 가장 비싼 것은 알파벳 순서 등으로 콘솔에 모델을 쓰는 것입니다. 도서관 프로젝트: 첫 번째 클래스: BookEntity{ Integer id; 문자열 이름Book; 정수 yearCreat; 정수 autorId; } 두 번째 클래스: AutorEntity{ Integer id; 문자열 firstNameAutor; 문자열 lastNameAutor; } 데이터베이스 채우기(이해하기 쉽도록 현실적인 이름 제시), 구현: 엔터티, 저장소, 서비스, 표준 및 테이블 간 쿼리 생성(누가 어떤 책을 썼는지, 어떤 책이 먼저 쓰여졌는지, 어떤 책이 쓰여졌는지) 1800년부터 1900년까지? 작가 중 가장 많은 책을 쓴 사람은 누구입니까?); "라이브러리" 프로젝트 데이터베이스 작성 예 도서 테이블 BookEntity(id=1, nameBook=Woe from Wit, yearCreat=1824,authorId=1) BookEntity(id=2, nameBook=War and Peace, yearCreat=1863,authorId=2) BookEntity(id=3, nameBook= Mtsyri, yearCreat=1838,authorId=3) BookEntity(id=4, nameBook=Eugene Onegin, yearCreat=1833,authorId=4) 작성자 테이블 AuthorEntity(id=1, firstNameAuthor=Alexander, lastNameAuthor=Griboyedov) AuthorEntity(id=2 , firstNameAuthor=Lev, lastNameAuthor=Tolstoy) AuthorEntity(id=3, firstNameAuthor=Mikhail, lastNameAuthor=Lermontov) AuthorEntity(id=4, firstNameAuthor=Alexander, lastNameAuthor=Pushkin) 행운을 빕니다,뵙겠습니다!
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION