JavaRush /Blog Java /Random-ES /Entidades JPA y relaciones DB
Nikita Koliadin
Nivel 40
Днепр

Entidades JPA y relaciones DB

Publicado en el grupo Random-ES

Entidades JPA y relaciones DB

¡Buenos días compañeros!
Entidades JPA y relaciones DB - 1
Este material está destinado a aquellos que ya tienen conocimientos sobre la organización de bases de datos (en adelante, simplemente DB - "Base de datos"), conocimientos mínimos de cómo funciona el mapeo relacional de objetos (en adelante, simplemente ORM ) y sus implementaciones, como Hibernate / JPA. . Si no está familiarizado con esto, le aconsejo que comience con JDBC y solo luego pase al modelo ORM. ¡Te lo advertí y no asumo ninguna responsabilidad por tu psique después de leer este artículo sin la preparación adecuada! :) Empecemos a arreglar todo en orden. En primer lugar, profundizaremos un poco en la teoría, sólo un poquito. En segundo lugar, descubriremos cómo hacer esto en el Java favorito de todos. También escribiremos con usted una hoja de referencia del proyecto, que consolidará nuestra comprensión del tema y servirá como plantilla sobre CÓMO se debe realizar el mapeo . ¡ Hagamoslo!

¿Qué es la entidad?

Una Entidad es un objeto de la vida real (por ejemplo, un automóvil) que tiene atributos (puertas, RUEDAS , motor). Entidad BD: En este caso nuestra entidad se almacena en una BD, todo es sencillo. Por qué y cómo colocamos el automóvil en la base de datos; lo veremos más adelante.

¿Qué son las relaciones DB?

Hace mucho tiempo, en el reino lejano, se creó una base de datos relacional . En esta base de datos, los datos se presentaron en forma de tablas. Pero incluso el burro de Shrek entendió que era necesario crear un mecanismo para interconectar estas mesas. Como resultado, aparecieron 4 relaciones DB :
  1. Cara a cara
  2. Uno a muchos
  3. Muchos a uno
  4. Muchos a muchos
Si estás viendo todo esto por primera vez, te lo vuelvo a advertir: irá a peor: piensa en salir a caminar. Analizaremos todas estas relaciones usando un ejemplo y entenderemos la diferencia entre ellas.

Ejemplo de terror

Tendremos un proyecto que tendrá 5 ramas: master, donde habrá una descripción del proyecto, y 1 rama para cada relación de BD. Cada rama contendrá scripts SQL para crear una base de datos y llenarla con datos de prueba, además de una clase de entidad con mapeo de anotaciones. También habrá un archivo de configuración de Hibernate para cada rama. Usaré la base de datos integrada H2 para el proyecto para no distraerme con aspectos individuales de la base de datos en la nube o la base de datos externa. Siguiendo el enlace, instale H2 DB en su aspiradora. Describiré cada paso en 1 rama, el resto son solo los puntos clave. Al final haremos un resumen. Ir. Este es un enlace a la rama maestra de mi proyecto.

Relación uno a uno

Enlace a sucursal aquí .
  1. Necesitamos conectar H2 DB a nuestro proyecto. Aquí debemos enfatizar que necesitamos Ultimate IDEA para trabajar cómodamente con DB y otras cosas. Si ya lo tiene, vaya directamente a la conexión DB. Vaya a la pestaña Base de datos y haga lo que se muestra en la captura de pantalla:

    Entidades JPA y relaciones DB - 2

    A continuación pasamos a la configuración de la base de datos. Puedes ingresar tus datos, e incluso tu DBMS, repito, yo uso H2 DB por simplicidad.

    Entidades JPA y relaciones DB - 3

    A continuación, configuremos el circuito. Este paso es opcional pero se recomienda si tiene varios esquemas en la base de datos.

    Entidades JPA y relaciones DB - 4

    Aplique la configuración y al final deberíamos obtener algo como esto:

    Entidades JPA y relaciones DB - 5
  2. Creamos la base de datos y configuramos el acceso a ella desde IDEA. Ahora necesitas crear tablas en él y completarlas con algunos datos. Por ejemplo, tomaré dos entidades: Autor y Libro. Un libro puede tener un autor, varios autores o no tener uno. En este ejemplo crearemos todo tipo de conexiones. Pero en este punto, una relación uno a uno. Creemos el script correspondiente que crea tablas DB :

    DROP TABLE IF EXISTS PUBLIC.BOOK;
    
    CREATE TABLE PUBLIC.BOOK (
      ID         INTEGER      NOT NULL AUTO_INCREMENT,
      NAME       VARCHAR(255) NOT NULL,
      PRINT_YEAR INTEGER(4)   NOT NULL,
      CONSTRAINT BOOK_PRIMARY_KEY PRIMARY KEY (ID)
    );
    
    DROP TABLE IF EXISTS PUBLIC.AUTHOR;
    
    CREATE TABLE PUBLIC.AUTHOR (
      ID          INTEGER      NOT NULL AUTO_INCREMENT,
      FIRST_NAME  VARCHAR(255) NOT NULL,
      SECOND_NAME VARCHAR(255) NOT NULL,
      BOOK_ID     INTEGER      NOT NULL UNIQUE,
      CONSTRAINT AUTHOR_PRIMARY_KEY PRIMARY KEY (ID),
      CONSTRAINT BOOK_FOREIGN_KEY FOREIGN KEY (BOOK_ID) REFERENCES BOOK (ID)
    );

    Y ejecutémoslo:

    Entidades JPA y relaciones DB - 6

    Resultado de la ejecución en la consola:

    Entidades JPA y relaciones DB - 7

    Resultado en base de datos:

    Entidades JPA y relaciones DB - 8
  3. Veamos un diagrama de nuestras tablas. Para hacer esto, RMB en nuestra base de datos:

    Entidades JPA y relaciones DB - 9

    Resultado:

    Entidades JPA y relaciones DB - 10

    En el diagrama UML podemos ver todas las claves primarias y externas, también vemos la conexión entre nuestras tablas.

  4. Escribamos un script que llene nuestra base de datos con datos de prueba:

    INSERT INTO PUBLIC.BOOK (NAME, PRINT_YEAR)
    VALUES ('First book', 2010),
           ('Second book', 2011),
           ('Third book', 2012);
    
    INSERT INTO PUBLIC.AUTHOR (FIRST_NAME, SECOND_NAME, BOOK_ID)
    VALUES ('Pablo', 'Lambado', 1),
           ('Pazo', 'Zopa', 2),
           ('Lika', 'Vika', 3);

    Quiero decir, ¿qué pasa? La relación uno a uno es necesaria cuando la entidad de una tabla está relacionada con una entidad de otra (o no está relacionada en absoluto si NOT NULL se elimina de BOOK_ID). En nuestro ejemplo, un libro DEBE tener un autor. Ninguna otra manera.

  5. Ahora lo más interesante es ¿cómo conectar una clase Java con entidades DB? Muy simple. Creemos dos clases Libro y Autor. Usando un ejemplo, analizaré la clase 1 y los campos clave de comunicación. Tomemos la clase Autor como ejemplo :

    @Data
    @Entity
    @DynamicInsert
    @DynamicUpdate
    @Table(name = "AUTHOR")
    public class Author {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "ID", nullable = false)
        private Long id;
    
        @Column(name = "FIRST_NAME", nullable = false)
        private String firstName;
    
        @Column(name = "SECOND_NAME", nullable = false)
        private String secondName;
    
        @OneToOne
        @JoinColumn(name = "BOOK_ID", unique = true, nullable = false)
        private Book book;
    }
Vamos a resolverlo en orden:
  1. Todos los campos de la clase repiten los atributos de la entidad de base de datos.
  2. @Data (de Lombok ) dice que para cada campo se creará un getter y un setter, será igual, se anulará el código hash y se generará un método toString.
  3. @Entity dice que la clase dada es una entidad y está asociada con una entidad de base de datos.
  4. @DynamicInsert y @DynamicUpdate dicen que las inserciones y actualizaciones dinámicas se realizarán en la base de datos. Estas son configuraciones de Hibernación más profundas que le serán útiles para que tenga el procesamiento por lotes CORRECTO.
  5. @Table (nombre = "AUTHOR") vincula la clase Libro a la tabla DB AUTHOR.
  6. @Id dice que este campo es la clave principal.
  7. @GeneratedValue (estrategia = GenerationType.IDENTITY) – estrategia de generación de clave principal.
  8. @Column (nombre = "ID", anulable = falso) asocia un campo con un atributo de base de datos y también dice que el campo de base de datos dado no puede ser nulo. Esto también es útil al generar tablas a partir de entidades. El proceso inverso a cómo creamos ahora nuestro proyecto, esto es necesario en las bases de datos de prueba para las pruebas unitarias.
  9. @OneToOne dice que el campo dado es un campo de relación uno a uno.
  10. @JoinColumn (nombre = "BOOK_ID", único = verdadero, anulable = falso): se creará una columna BOOK_ID, que es única y no nula.
En el reverso (en la clase Libro ), también necesitamos realizar una conexión Uno a Uno e indicar el campo en el que se produce el mapeo. @OneToOne(mappedBy = "libro"): en este ejemplo, este es el campo libro de la clase Autor. JPA los vinculará ella misma. A primera vista, puede parecer que hay un lío de anotaciones, pero en realidad es muy conveniente y con experiencia las agregarás automáticamente sin siquiera pensarlo.
  1. Ahora configuremos Hibernate. Para hacer esto, cree un archivo hibernate.cfg.xml :

    <?xml version='1.0' encoding='utf-8'?>
    <!DOCTYPE hibernate-configuration PUBLIC
            "-//Hibernate/Hibernate Configuration DTD//EN"
            "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
    
    <hibernate-configuration>
        <session-factory>
            <property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>
            <property name="hibernate.connection.driver_class">org.h2.Driver</property>
    
            <property name="hibernate.connection.url">jdbc:h2:~/db/onetoone</property>
            <property name="hibernate.connection.username">root</property>
            <property name="hibernate.connection.password"/>
    
            <property name="hibernate.hbm2ddl.auto">update</property>
    
            <property name="hibernate.show_sql">true</property>
            <property name="hibernate.format_sql">true</property>
            <property name="hibernate.use_sql_comments">true</property>
    
            <property name="hibernate.generate_statistics">true</property>
    
            <property name="hibernate.jdbc.batch_size">50</property>
            <property name="hibernate.jdbc.fetch_size">50</property>
    
            <property name="hibernate.order_inserts">true</property>
            <property name="hibernate.order_updates">true</property>
            <property name="hibernate.jdbc.batch_versioned_data">true</property>
    
            <mapping class="com.qthegamep.forjavarushpublication2.entity.Book"/>
            <mapping class="com.qthegamep.forjavarushpublication2.entity.Author"/>
        </session-factory>
    </hibernate-configuration>
Descripción de propiedades :
  1. hibernate.dialect es el dialecto del DBMS que hemos elegido.
  2. hibernate.connection.driver_class — Clase de controlador de nuestra base de datos.
  3. hibernate.connection.url - utl de nuestra base de datos. Puedes tomarlo desde el primer punto donde configuramos DB.
  4. hibernate.connection.username: nombre de usuario de la base de datos.
  5. hibernate.connection.password: contraseña de usuario de base de datos.
  6. hibernate.hbm2ddl.auto: configuración de la generación de tablas. Si se actualiza, entonces no genera si ya se ha creado, solo lo actualiza.
  7. hibernate.show_sql: si se muestran consultas de base de datos.
  8. hibernate.format_sql: si se deben formatear las consultas de base de datos. Si no, estarán todos en una misma línea. Recomiendo encenderlo.
  9. hibernate.use_sql_comments: comentarios de consultas de base de datos. Si se trata de una inserción, se escribe un comentario encima de la solicitud indicando que la solicitud es del tipo Insertar.
  10. hibernate.generate_statistics: genera registros. Recomiendo y recomiendo configurar el registro al máximo. Leer los registros aumentará sus posibilidades de trabajar correctamente con el ORM.
  11. hibernate.jdbc.batch_size: tamaño máximo de lote.
  12. hibernate.jdbc.fetch_size: tamaño máximo de recuperación.
  13. hibernate.order_inserts: permite inserciones dinámicas.
  14. hibernate.order_updates: permite actualizaciones dinámicas.
  15. hibernate.jdbc.batch_versioned_data: permite el procesamiento por lotes. Mire su DBMS: no todo el mundo lo admite.
  16. clase de mapeo: clases que son nuestras entidades. Es necesario enumerar todo.
  1. Ahora nuestra esencia debe ser determinada. Podemos comprobar esto en la pestaña de persistencia:

    Entidades JPA y relaciones DB - 11

    Resultado:

    Entidades JPA y relaciones DB - 12
  2. También necesitamos configurar los datos de asignación:

    Entidades JPA y relaciones DB - 13 Entidades JPA y relaciones DB - 14

    Resultados: Hemos realizado un mapeo Uno a Uno. El material es sólo para fines informativos, los detalles se encuentran en las referencias.

Relación uno a muchos

Enlace a sucursal aquí . Ya no publicaré el código en el artículo porque ya es demasiado largo. Miramos todo el código en GitHub.
  1. Como resultado de ejecutar el script de inicialización, obtenemos lo siguiente:

    Entidades JPA y relaciones DB - 15

    ¿Sientes la diferencia con la tabla anterior?

  2. Diagrama:

    Entidades JPA y relaciones DB - 16

    Relación uno a muchos: un autor puede tener varios libros. La entidad izquierda corresponde a una o más derechas.

  3. La diferencia en el mapeo estará en las anotaciones y los campos:

    Aparece un campo en la clase Autor :

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "author")
    private Set<Book> books;

    Ya es un conjunto, ya que podemos tener varios libros. @OneToMany está hablando de tipo de actitud. FetchType.Lazy dice que no necesitamos cargar la lista completa de libros si no se especifica en la solicitud. También hay que decir que este campo NO SE PUEDE agregar a toString; de lo contrario, comenzaremos a fumar un StackOverflowError. Mi amado Lombok se encarga de esto:

    @ToString(exclude = "books")

    En la clase de Libro hacemos comentarios de muchos a uno:

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "AUTHOR_ID", nullable = false)
    private Author author;

    Aquí concluimos que Uno a Muchos es la imagen especular de Muchos a Uno y viceversa. Cabe destacar que Hibernate no sabe nada sobre comunicaciones bidireccionales. Para él, se trata de dos conexiones diferentes: una en una dirección y la otra en la dirección opuesta.

  4. No ha cambiado mucho en hibernate.cfg.xml .

  5. Persistencia:

    Entidades JPA y relaciones DB - 17

Relación de muchos a uno

Dado que Muchos a Uno es una imagen especular de Uno a Muchos, habrá pocas diferencias. Enlace a sucursal aquí .
  1. Como resultado de ejecutar el script de inicialización, obtenemos el siguiente resultado:

    Entidades JPA y relaciones DB - 18
  2. Diagrama:

    Entidades JPA y relaciones DB - 19
  3. La diferencia en el mapeo estará en las anotaciones y los campos:

    Ya no hay un conjunto en la clase Autor , ya que se pasó a la clase Libro .

  4. hibernación.cfg.xml

  5. Persistencia:

    Entidades JPA y relaciones DB - 20

Relación de muchos a muchos

Pasemos a la relación más interesante. Esta relación, de acuerdo con todas las reglas de la decencia e indecencia, se crea mediante una tabla adicional. Pero esta tabla no es una entidad. Interesante, ¿verdad? Echemos un vistazo a esta mierda. Enlace a sucursal aquí .
  1. Mire el script de inicialización , aquí aparece una tabla HAS adicional. Obtenemos algo así como el autor tiene el libro.

    Como resultado de ejecutar el script, obtendremos las siguientes tablas:

    Entidades JPA y relaciones DB - 21
  2. Diagrama:

    Entidades JPA y relaciones DB - 22

    En nuestro ejemplo, resulta que un libro puede tener muchos autores y un autor puede tener muchos libros. Pueden superponerse.

  3. Las clases de mapeo tendrán conjuntos dentro de las clases. Pero como dije, la tabla HAS no es una entidad.

    Clase de autor :

    @ManyToMany
    @JoinTable(name = "HAS",
            joinColumns = @JoinColumn(name = "AUTHOR_ID", referencedColumnName = "ID"),
            inverseJoinColumns = @JoinColumn(name = "BOOK_ID", referencedColumnName = "ID")
    )
    private Set<Book> books;

    @ManyToMany es un tipo de relación.

    @JoinTable : esto es exactamente lo que conectará el atributo con una tabla HAS adicional. En él especificamos dos atributos que apuntarán a las claves primarias de dos entidades.

    Clase de libro :

    @ManyToMany(fetch = FetchType.LAZY, mappedBy = "books")
    private Set<Author> authors;

    Aquí indicamos FetchType y el campo que usaremos para mapear.

  4. Nuestro hibernate.cfg.xml nuevamente permaneció sin cambios (no tomo en cuenta el hecho de que creamos una nueva base de datos para cada rama).

  5. Persistencia:

    Entidades JPA y relaciones DB - 23

Interrogación

Entonces, examinamos superficialmente los tipos de relaciones de base de datos y descubrimos cómo implementarlas en el modelo ORM. Escribimos un proyecto de prueba que demuestra todas las conexiones y descubrimos cómo configurar hibernate/jpa. Uf.

Enlaces útiles

Mis artículos anteriores: PD: Puede haber errores y deficiencias en el texto. PPS El autor estaba fumando algo extraño mientras escribía este artículo. ¡Gracias por su atención!
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION