JavaRush /Blogue Java /Random-PT /Spring não é assustador, ou como fazer uma pergunta sobre...
Павел
Nível 11

Spring não é assustador, ou como fazer uma pergunta sobre banco de dados

Publicado no grupo Random-PT
CONTEÚDO DO CICLO DE ARTIGOS Hoje estamos finalizando o trabalho com o banco de dados como parte do nosso projeto. Se você fez tudo corretamente, deverá ter um pom com as seguintes dependências:
<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>
E esta é a estrutura do projeto: Spring não é assustador, ou como fazer uma pergunta sobre banco de dados - 1 Sabe de quem não lembramos há muito tempo? Este é application.yml, não falamos muito sobre isso em um dos artigos anteriores. Agora vamos em frente e excluí-lo! Sim, sim, exclua e pronto! Se lançarmos o projeto agora, tudo funcionará como antes, tente isto. Isso aconteceu porque o próprio Spring foi configurado com configurações padrão. Agora precisamos retornar nosso arquivo yml para a pasta de recursos, ainda precisaremos dele: application.yml (o nome deve ser o mesmo)
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
Da última vez, implementamos diversas consultas ao banco de dados usando métodos da interface 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);
}
Se você leu sobre SQL , como pedi da última vez, saiba que tais ações com o banco de dados devem ser realizadas por meio de consultas SQL. Mas não há nenhum indício disso no projeto; mesmo nos logs do console não há nada semelhante. Vamos encontrá-los, abrir application.yml, encontrar a linha show-sql: ali (show sql) e alterar false para true. Lançamos o projeto e olhamos no console, os logs são preenchidos com novas entradas muito parecidas com SQL, na verdade, a maioria delas não são difíceis de entender, por exemplo:
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))
Mas esta entrada pode levantar muitas questões devido aos seus pontos de interrogação:
Hibernate: insert into fruit_table (fruit_name, provider_code, id_fruit) values (?, ?, ?)
Vamos pensar logicamente: em primeiro lugar, vemos a palavra Hibernate, que significa que esse cara reservado colocou sua pata peluda aqui. Depois de ler sobre ele na Internet, ficamos sabendo que o Sr. Hiber é uma implementação do modelo ORM. O modelo objeto-relacional descreve os relacionamentos entre objetos de software e registros no banco de dados. Fixada esta ideia, continuamos a pensar logicamente: Por um lado, temos um objeto FruitEntity , que possui três campos: Integer id; String nomeDaFruta; Código do provedor inteiro. Por outro lado, temos uma tabela no banco de dados fruta_tabela com campos id_fruta tipo inteiro, fruta_nome tipo varchar(255) , provedor_código tipo inteiro. Grosso modo, o Hibernate pega um objeto FruitEntity , extrai os valores dos campos do objeto e os grava nos campos correspondentes da tabela. Tenho uma pergunta para você: Olha, na classe InitiateUtils implementamos o preenchimento da tabela de frutas, mas por algum motivo definimos o valor para apenas dois campos, onde fica o terceiro?
new FruitEntity()
        .setFruitName("Fruit1")//раз
        .setProviderCode(Math.abs(new Random().nextInt() % 10)),//два
                                            //три???
Tenho certeza de que você descobrirá isso por si mesmo. Além disso, abordamos brevemente esse assunto no penúltimo artigo. Primeiro descubra qual campo não está aqui e então você entenderá tudo. Muito bem, o Hiber gerou vários pedidos para nós. Mas não somos cegos, vamos implementar mais alguns métodos da interface JpaRepository<> na classe FruitService
//возвращает запись из таблицы по 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);
}
Implemente os mesmos métodos na classe ProviderService. Em seguida, use-os na classe InitiateUtils para FruitEntity e ProviderEntity e imprima o resultado no console. (A propósito, se você não sabia, você pode escrever rapidamente “System.out.println()” digitando sout e pressionando enter, a mesma coisa funciona com “public static void main(String[] args){} ”basta digitar psvm e pronto, etc. ). Acho que você já lidou com isso e estamos prontos para seguir em frente. Vamos para a interface FruitRepository e começar a digitar nela (ou seja, digitar e não copiar) o seguinte método: List<FruitEntity> f Você deve obter o seguinte: Spring não é assustador, ou como fazer uma pergunta sobre banco de dados - 2 Basta chamar o método como se estivesse compondo uma consulta: findById(Integer id ) - encontra um objeto por id; countFruitEntityByFruitName(String name) - contará a quantidade de frutas com um nome específico; Estas são consultas geradas pelo nome do método; não deixe de ler sobre elas e implementar o método entre(Integer from, Integer to) na classe FruitService para pesquisar List<FruitEntity> pelos valores do campo Provider_code incluído em um determinado intervalo e exibir o resultado do trabalho no console. Por exemplo: encontre todas as frutas cujo número de fornecedor esteja entre 5 e 7. Não se apresse em ler mais até implementar o método, não demorará muito. Como você deve ter lido no artigo sobre consultas por nome de método: “Você não pode escrever todas as consultas assim, mas as simples podem ser escritas”. Para consultas mais complexas, a anotação @Query é usada e JPQL é usado em vez de SQL (observe também este artigo) Para nosso projeto, você pode fazer consultas JOIN, como esta:
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();

}
Uma consulta SQL padrão seria: "selecione fruta_tabela.nome_de_fruta, tabela_de_provedor.nome_de_provedor de tabela_de_fruta à esquerda, junte-se a tabela_de_fruta em tabela_de_fruta.código_de_provedor = tabela_de_provedor.id". Aqui você pode facilmente estabelecer uma correspondência: f ruit_table é FruitEntiy f, onde FruitEntiy é o tipo da variável, f é o seu nome, ou seja, SQL trabalha com tabelas e campos, e JPQL com objetos e seus campos. Novamente fruta_tabela.fruit_name é f.fruitName ; Como trabalhamos com objetos, podemos gerar o objeto: Vamos escrever outro método FruitRepository
@Query("select f from  FruitEntity f  join ProviderEntity p on f.providerCode = p.id")
List<FruitEntity> joinFruit();
Vamos implementar os dois métodos na classe FruitService
public List<String> joinString(){
   return fruitRepository.joinSting();
}

public List<FruitEntity> joinFruit(){
    return fruitRepository.joinFruit();
}
Não parece ruim, mas eles ainda usam o bom e velho SQL para consultas complexas
@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();
E usamos todos eles na classe 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);
        }
Lançamos o projeto e vemos novos logs no console: Tabela de frutas e seus fornecedores Fruta1,null Fruta2,Provedor5 Fruta3,Provedor2 Fruta4,Provedor5 Fruta5,null Fruta6,null Fruta7,null Fruta8,null Fruta9,null Tabela de frutas e seus fornecedores FruitEntity(id= 2, frutaName=Fruit2, ProviderCode=5) FruitEntity(id=3, FruitName=Fruit3, ProviderCode=2) FruitEntity(id=4, FruitName=Fruit4, ProviderCode=5) Tabela de frutas e seus fornecedores Fruit2 ,Provider5 Fruit3,Provider2 Fruit4 ,Provider5 Sim, se você já está cansado de “pseudo” e apenas consultas SQL no console, você pode retornar false em seu lugar no arquivo yaml. Por que há nulo na primeira tabela, você descobrirá se ler sobre JOIN SQL . E assim terminamos as consultas ao banco de dados, tenho certeza que você ainda tem muitas dúvidas, mas espero que procure respostas para elas, tentei destacar os caminhos de busca. Vamos tentar resumir tudo o que aprendemos durante esse período: 1. Você pode executar um servidor web no Spring e não é difícil. 2. Para entender como tudo funciona, é preciso mergulhar na teoria. Sobre o livro Artigo sobre spring Artigo sobre coisas úteis 3. Para que o entendimento se transforme em código físico, você precisa codificar e, antes de prosseguir, colocar as mãos em projetos simples no spring-boot. E é melhor não copiar o código escrito, mas reescrevê-lo. Vou postar aqui o projeto no qual você e eu estamos trabalhando, mas contarei com a sua consciência e tenho certeza que você não copiará e colará sem pensar. Link para o repositório git clone https://FromJava@bitbucket.org/FromJava/jd.git Para quem não sabe usar este link recomendo implementar dois projetos de treinamento: Projeto sobre pintura de carros: Primeira aula: CarEntity{ Inteiro eu ia; String nomeModelo; Cor da corda; } Segunda classe: ColorEntity{ ID inteiro; Cor da corda; Preço inteiro; } Preencha o banco de dados (invente nomes realistas para que seja mais fácil de entender), implemente: , entidade, repositórios, serviços, crie consultas padrão e entre tabelas (Quanto custa pintar um BMW de vermelho? Qual é a cor o mais caro?Escreva os modelos no console em ordem alfabética e etc.); Projeto de biblioteca: Primeira classe: BookEntity{ Integer id; String nomeLivro; Ano inteiroCreat; AutorId inteiro; } Segunda classe: AutorEntity{ ID inteiro; String primeiroNomeAutor; String últimoNomeAutor; } Preencha o banco de dados (invente nomes realistas para que seja mais fácil de entender), implemente: entidade, repositórios, serviços, crie consultas padrão e entre tabelas (Quem escreveu qual livro? Qual livro foi escrito primeiro? Quais livros foram escritos de 1800 a 1900? Qual dos autores escreveu mais livros?); Exemplos de preenchimento da base de dados do projeto "Biblioteca" Tabela de livros BookEntity(id=1, nameBook=Ai de Wit, yearCreat=1824, authorId=1) BookEntity(id=2, nameBook=Guerra e Paz, yearCreat=1863, authorId=2) BookEntity(id=3, nameBook= Mtsyri, yearCreat=1838, authorId=3) BookEntity(id=4, nameBook=Eugene Onegin, yearCreat=1833, authorId=4) Tabela de autores 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) Boa sorte a todos, nos vemos novamente!
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION