JavaRush /Blog Java /Random-ES /La primavera no da miedo, o cómo hacer una pregunta sobre...
Павел
Nivel 11

La primavera no da miedo, o cómo hacer una pregunta sobre la base de datos

Publicado en el grupo Random-ES
CONTENIDOS DEL CICLO DE ARTÍCULOS Hoy estamos ultimando el trabajo con la base de datos como parte de nuestro proyecto. Si hiciste todo correctamente, entonces deberías tener un pom con las siguientes dependencias:
<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>
Y aquí está la estructura del proyecto: ¿ La primavera no da miedo, o cómo hacer una pregunta sobre una base de datos - 1 Sabes de quién hace tiempo que no nos acordamos? Este es application.yml, no hablamos mucho de ello en uno de los artículos anteriores. ¡Ahora sigamos adelante y eliminémoslo! ¡Sí, sí borra y listo! Si lanzamos el proyecto ahora, todo funcionará como antes, prueba esto. Esto sucedió porque el propio Spring estaba configurado con la configuración predeterminada. Ahora necesitamos devolver nuestro archivo yml a la carpeta de recursos, aún lo necesitaremos: application.yml (el nombre debe ser el mismo)
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
La última vez implementamos varias consultas a la base de datos usando métodos de la interfaz 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);
}
Si lees sobre SQL , como te pedí la última vez, entonces debes saber que dichas acciones con la base de datos deben realizarse mediante consultas SQL. Pero no hay ningún indicio de esto en el proyecto, ni siquiera en los registros de la consola hay nada parecido. Busquémoslos, abramos application.yml, busquemos la línea show-sql: allí (show sql) y cambiemos falso a verdadero. Lanzamos el proyecto y miramos la consola, los registros están llenos de nuevas entradas muy similares a SQL, de hecho, la mayoría de ellas no son difíciles de entender, por ejemplo:
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))
Pero esta entrada puede generar muchas preguntas debido a sus signos de interrogación:
Hibernate: insert into fruit_table (fruit_name, provider_code, id_fruit) values (?, ?, ?)
Pensemos de forma lógica: en primer lugar, vemos la palabra Hibernar, que significa que este tipo reservado ha puesto su pata peluda aquí. Después de leer sobre él en Internet, descubrimos que el Sr. Hiber es una implementación del modelo ORM. El modelo relacional de objetos describe las relaciones entre los objetos de software y los registros en la base de datos. Una vez fijada esta idea, seguimos pensando de forma lógica: por un lado, tenemos un objeto FruitEntity , tiene tres campos: Integer id; Cadena de nombre de fruta; Código de proveedor entero. Por otro lado, tenemos una tabla en la base de datos fruit_table con campos id_fruit tipo entero, fruit_name tipo varchar(255) , proveedor_code tipo entero. En términos generales, Hibernate toma un objeto FruitEntity , extrae los valores de los campos del objeto y los escribe en los campos de la tabla correspondiente. Tengo una pregunta para ti: mira, en la clase InitiateUtils implementamos el llenado de la tabla de frutas, pero por alguna razón establecimos el valor en solo dos campos, ¿dónde está el tercero?
new FruitEntity()
        .setFruitName("Fruit1")//раз
        .setProviderCode(Math.abs(new Random().nextInt() % 10)),//два
                                            //три???
Estoy seguro de que lo descubrirás por ti mismo; además, abordamos brevemente este tema en el penúltimo artículo. Primero, averigüe qué campo no está aquí y luego comprenderá todo. Bien, bien hecho, Hiber generó un montón de solicitudes para nosotros. Pero no estamos ciegos, implementemos algunos métodos más desde la interfaz JpaRepository<> en la clase FruitService
//возвращает запись из таблицы по id
public Optional<FruitEntity> getById(Integer id){
   return fruitRepository.findById(id);
}

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

//возвращает true o false при поиске в таблице Фруктов un objetoа который соответствует типу FruitEntity o принадлежит к типу un objetoа который наследуется от FruitEntity
public Boolean exist(Example<? extends FruitEntity> example){
    return fruitRepository.exists(example);
}
Implemente los mismos métodos en la clase ProviderService. Luego utilícelos en la clase InitiateUtils para FruitEntity y ProviderEntity e imprima el resultado en la consola. (Por cierto, si no lo sabías, puedes escribir rápidamente “System.out.println()” escribiendo sout y presionando enter, lo mismo funciona con “public static void main(String[] args){} "Simplemente escriba psvm y listo, etc. ). Creo que ya lo has solucionado y estamos listos para seguir adelante. Vayamos a la interfaz FruitRepository y comencemos a escribir en ella (es decir, escribir y no copiar) el siguiente método: List<FruitEntity> f Debería obtener lo siguiente. La primavera no da miedo, o cómo hacer una pregunta sobre una base de datos - 2 Simplemente llame al método como si estuviera redactando una consulta: findById(Integer id ) - encuentra un objeto por identificación; countFruitEntityByFruitName(String name): contará la cantidad de frutas con un nombre específico; Estas son consultas generadas por el nombre del método; asegúrese de leer sobre ellas e implementar el método entre(Integer from, Integer to) en la clase FruitService para buscar List<FruitEntity> por los valores del campo código_proveedor incluido en un intervalo determinado y mostrar el resultado del trabajo en la consola. Por ejemplo: busque todas las frutas cuyo número de proveedor esté entre 5 y 7. No se apresure a leer más hasta que implemente el método, no tomará mucho tiempo. Como habrás leído en el artículo sobre consultas por nombre de método: "No se pueden escribir todas las consultas de esta manera, pero se pueden escribir consultas simples". Para consultas más complejas se usa la anotación @Query y se usa JPQL en lugar de SQL (también toma nota de este artículo). Para nuestro proyecto, puedes hacer 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();

}
Una consulta SQL estándar sería: "seleccione fruit_table.fruit_name, proveedor_table.provider_name de fruit_table izquierda unirse proveedor_table en fruit_table.provider_code = proveedor_table.id". Aquí puedes establecer fácilmente una correspondencia: f ruit_table es FruitEntiy f, donde FruitEntiy es el tipo de variable, f es su nombre, es decir, SQL trabaja con tablas y campos, y JPQL con objetos y sus campos. Nuevamente fruit_table.fruit_name es f.fruitName ; Como trabajamos con objetos, podemos generar el objeto: escribamos otro método FruitRepository
@Query("select f from  FruitEntity f  join ProviderEntity p on f.providerCode = p.id")
List<FruitEntity> joinFruit();
Implementemos ambos métodos en la clase FruitService.
public List<String> joinString(){
   return fruitRepository.joinSting();
}

public List<FruitEntity> joinFruit(){
    return fruitRepository.joinFruit();
}
No suena mal, pero todavía usan el viejo SQL para consultas complejas.
@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",  //по идее эту портянку надо засунуть в Cómoой нибудь  Enum
        nativeQuery = true) //нужно только пометить только nativeQuery = true
ListList<String> joinSqlFruit();
Y los usamos todos en la clase 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);
        }
Lanzamos el proyecto y vemos nuevos logs en la consola: Tabla de frutas y sus proveedores Fruit1,null Fruit2,Provider5 Fruit3,Provider2 Fruit4,Provider5 Fruit5,null Fruit6,null Fruit7,null Fruit8,null Fruit9,null Tabla de frutas y sus proveedores FruitEntity(id= 2, fruitName=Fruit2, provedorCode=5) FruitEntity(id=3, fruitName=Fruit3, provedorCode=2) FruitEntity(id=4, fruitName=Fruit4, provedorCode=5) Tabla de frutas y sus proveedores Fruit2 ,Provider5 Fruit3,Provider2 Fruit4 ,Provider5 Sí, si ya está cansado de las consultas “pseudo” y solo SQL en la consola, puede devolver false en su lugar en el archivo yaml. Por qué hay un valor nulo en la primera tabla, lo descubrirá si lee sobre JOIN SQL . Y así, terminamos con las consultas a la base de datos, estoy seguro de que todavía tienes muchas preguntas, pero espero que busques respuestas, intenté resaltar las rutas de búsqueda. Intentemos resumir todo lo que hemos aprendido durante este tiempo: 1. Puedes ejecutar un servidor web en Spring y no es difícil. 2. Para comprender cómo funciona todo, es necesario profundizar en la teoría. Acerca del libro Artículo sobre Spring Artículo sobre cosas útiles 3. Para que la comprensión se convierta en código físico, es necesario codificar y, antes de continuar, tener en sus manos proyectos simples en Spring-Boot. Y es mejor no copiar el código escrito, sino reescribirlo. Publicaré aquí el proyecto en el que tú y yo hemos estado trabajando, pero confiaré en tu conocimiento y estoy seguro de que no copiarás y pegarás sin pensar. Enlace al repositorio de clones de git https://FromJava@bitbucket.org/FromJava/jd.git Para aquellos que no saben utilizar este enlace recomiendo implementar dos proyectos de capacitación: Proyecto sobre pintura de autos: Primera clase: CarEntity{ Integer identificación; Nombre del modelo de cadena; Color de cuerda; } Segunda clase: ColorEntity{ Id. entero; Color de cuerda; Precio entero; } Llene la base de datos (proponga nombres realistas para que sea más fácil de entender), implemente: entidad, repositorios, servicios, cree consultas estándar y cruzadas (¿Cuánto cuesta pintar un BMW de rojo? ¿De qué color es? ¿el más caro? Escriba los modelos en la consola en orden alfabético, etc.); Proyecto de biblioteca: Primera clase: BookEntity{ Integer id; Nombre de cadenaLibro; Año enteroCreat; ID de autor entero; } Segunda clase: AutorEntity{ Id. entero; Cadena primerNombreAutor; Cadena apellidoAutor; } Llene la base de datos (proponga nombres realistas para que sea más fácil de entender), implemente: entidad, repositorios, servicios, cree consultas estándar y entre tablas (¿Quién escribió qué libro? ¿Qué libro se escribió primero? ¿Qué libros se escribieron? ¿de 1800 a 1900? ¿Cuál de los autores escribió más libros?); Ejemplos para completar la base de datos del proyecto "Biblioteca" Tabla de libros BookEntity(id=1, nombreLibro=Ay de Wit, añoCreat=1824, autorId=1) LibroEntidad(id=2, nombreLibro=Guerra y paz, añoCreat=1863, autorId=2) LibroEntidad(id=3, nombreLibro= Mtsyri, añoCreat=1838, autorId=3) BookEntity(id=4, nombreLibro=Eugene Onegin, añoCreat=1833, autorId=4) Tabla 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) ¡ Buena suerte a todos, nos vemos de nuevo!
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION