JavaRush /Java Blog /Random-IT /Entità JPA e relazioni DB
Nikita Koliadin
Livello 40
Днепр

Entità JPA e relazioni DB

Pubblicato nel gruppo Random-IT

Entità JPA e relazioni DB

Buona giornata, colleghi!
Entità JPA e relazioni DB - 1
Questo materiale è destinato a coloro che hanno già un'idea dell'organizzazione dei database (di seguito semplicemente DB - "Database"), una conoscenza minima di come funziona l'Object-Relational Mapping (di seguito semplicemente ORM ) e delle sue implementazioni, come Hibernate /APP . Se non hai familiarità con questo, ti consiglio di iniziare con JDBC e solo successivamente passare al modello ORM. Ti avevo avvertito e non mi assumo la responsabilità per la tua psiche dopo aver letto questo articolo senza un'adeguata preparazione! :) Iniziamo a occuparci di tutto in ordine. Innanzitutto, approfondiremo un po' la teoria, solo un po'. In secondo luogo, scopriremo come fare questa merda nel Java preferito da tutti. Scriveremo anche con te un cheat sheet del progetto, che consoliderà la nostra comprensione dell'argomento e servirà da modello per COME dovrebbe essere eseguita la mappatura . Facciamolo !

Cos'è l'Entità?

Un'entità è un oggetto della vita reale (ad esempio un'auto) che ha attributi (porte, RUOTE , motore). Entità DB: in questo caso la nostra entità è archiviata in un DB, tutto è semplice. Perché e come inseriamo l'auto nel database: lo vedremo più tardi.

Che cosa sono le relazioni DB?

Tanto tempo fa, in un regno lontano, venne creato un DB relazionale . In questo DB i dati venivano presentati sotto forma di tabelle. Ma anche l'asino di Shrek ha capito che era necessario creare un meccanismo per collegare questi tavoli. Di conseguenza, sono apparse 4 relazioni DB :
  1. Uno a uno
  2. Uno a molti
  3. Molti a uno
  4. Molti a molti
Se vedi tutto questo per la prima volta, ti avverto ancora una volta: peggiorerà: pensa a fare una passeggiata. Analizzeremo tutte queste relazioni utilizzando un esempio e comprenderemo la differenza tra loro.

Esempio dell'orrore

Avremo un progetto che avrà 5 rami: master, dove ci sarà una descrizione del progetto, e 1 ramo per ogni relazione DB. Ogni ramo conterrà script SQL per creare un DB e riempirlo con dati di test, oltre a una classe Entity con mappatura delle annotazioni. Ci sarà anche un file di configurazione di Hibernate per ogni ramo. Utilizzerò il DB incorporato H2 per il progetto in modo da non essere distratto dai singoli aspetti del DB cloud o del DB esterno. Seguendo il collegamento, installa H2 DB sul tuo aspirapolvere. Descriverò ogni passaggio in 1 ramo, il resto sono solo i punti chiave. Alla fine riassumeremo. Andare. Questo è un collegamento al ramo principale del mio progetto.

Relazione uno a uno

Link alla filiale qui .
  1. Dobbiamo connettere H2 DB al nostro progetto. Qui dobbiamo sottolineare che abbiamo bisogno di Ultimate IDEA per lavorare comodamente con DB e altre cose. Se lo hai già, vai direttamente alla connessione DB. Vai alla scheda Database e fai come nello screenshot:

    Entità JPA e relazioni DB - 2

    Successivamente passiamo alle impostazioni del DB. Puoi inserire i tuoi dati e anche il tuo DBMS; ripeto, utilizzo H2 DB per semplicità.

    Entità JPA e relazioni DB - 3

    Quindi, impostiamo il circuito. Questo passaggio è facoltativo ma consigliato se sono presenti più schemi nel database.

    Entità JPA e relazioni DB - 4

    Applica le impostazioni e alla fine dovremmo ottenere qualcosa del genere:

    Entità JPA e relazioni DB - 5
  2. Abbiamo creato il database e configurato l'accesso ad esso da IDEA. Ora devi creare delle tabelle al suo interno e riempirle con alcuni dati. Ad esempio, prenderò due entità: Autore e Libro. Un libro può avere un autore, può avere più autori o può non averne uno. In questo esempio creeremo tutti i tipi di connessioni. Ma a questo punto... relazione uno a uno. Creiamo lo script corrispondente che crea tabelle 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)
    );

    E eseguiamolo:

    Entità JPA e relazioni DB - 6

    Risultato dell'esecuzione nella console:

    Entità JPA e relazioni DB - 7

    Risultato nel DB:

    Entità JPA e relazioni DB - 8
  3. Diamo un'occhiata a un diagramma delle nostre tabelle. Per fare ciò, RMB sul nostro DB:

    Entità JPA e relazioni DB - 9

    Risultato:

    Entità JPA e relazioni DB - 10

    Sul diagramma UML possiamo vedere tutte le chiavi primarie e le chiavi esterne, vediamo anche la connessione tra le nostre tabelle.

  4. Scriviamo uno script che riempia il nostro DB con i dati di test:

    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);

    Voglio dire, cosa succede? La relazione uno-a-uno è necessaria quando l'entità di una tabella è correlata all'entità di un'altra (o non è affatto correlata se NOT NULL viene rimosso da BOOK_ID). Nel nostro esempio, un libro DEVE avere un autore. Nessun altro modo.

  5. Ora la cosa più interessante è come connettere una classe Java con entità DB? Molto semplice. Creiamo due classi Libro e Autore. Utilizzando un esempio, analizzerò la classe 1 e i campi chiave della comunicazione. Prendiamo come esempio la classe Author :

    @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;
    }
Scopriamolo in ordine:
  1. Tutti i campi della classe ripetono gli attributi dell'entità DB.
  2. @Data (da Lombok ) dice che per ogni campo verranno creati un getter e un setter, uguale, l'hashcode verrà sovrascritto e verrà generato un metodo toString.
  3. @Entity dice che la classe data è un'entità ed è associata a un'entità DB.
  4. @DynamicInsert e @DynamicUpdate affermano che gli inserimenti e gli aggiornamenti dinamici verranno eseguiti nel DB. Queste sono impostazioni di ibernazione più profonde che ti saranno utili in modo da avere il batch CORRETTO.
  5. @Table (name = "AUTHOR") associa la classe Book alla tabella DB AUTHOR.
  6. @Id dice che questo campo è la chiave primaria.
  7. @GeneratedValue (strategia = GenerationType.IDENTITY) – strategia di generazione della chiave primaria.
  8. @Column (name = "ID", nullable = false) associa un campo a un attributo DB e dice anche che il campo DB specificato non può essere nullo. Ciò è utile anche quando si generano tabelle da entità. Il processo inverso rispetto a come creiamo ora il nostro progetto, è necessario nei DB di test per i test unitari.
  9. @OneToOne dice che il campo indicato è un campo di relazione uno-a-uno.
  10. @JoinColumn (name = "BOOK_ID", unique = true, nullable = false) - verrà creata una colonna BOOK_ID, che è univoca e non nulla.
Sul retro (nella classe Book ) dobbiamo anche effettuare una connessione One-to-One e indicare il campo su cui avviene la mappatura. @OneToOne(mappedBy = "book") - in questo esempio, questo è il campo book della classe Author. L'APP li collegherà essa stessa. A prima vista può sembrare che ci sia un pasticcio di annotazioni, ma in realtà è molto comodo e con l'esperienza le aggiungerai automaticamente senza nemmeno pensarci.
  1. Ora configuriamo Hibernate. Per fare ciò, crea un file 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>
Descrizione delle proprietà :
  1. hibernate.dialect è il dialetto del DBMS che abbiamo scelto.
  2. hibernate.connection.driver_class — Classe del driver del nostro DB.
  3. hibernate.connection.url - utl del nostro DB. Puoi prenderlo dal primo punto in cui abbiamo configurato DB.
  4. hibernate.connection.username - Nome utente DB.
  5. hibernate.connection.password — Password utente DB.
  6. hibernate.hbm2ddl.auto - impostazione della generazione di tabelle. Se aggiorna, non genera se è già stato creato, ma lo aggiorna solo.
  7. hibernate.show_sql - se mostrare le query DB.
  8. hibernate.format_sql - se formattare le query DB. In caso contrario, saranno tutti su una riga. Consiglio di accenderlo.
  9. hibernate.use_sql_comments - commenti query DB. Se si tratta di un inserto, viene scritto un commento sopra la richiesta indicante che la richiesta è del tipo insert.
  10. hibernate.generate_statistics - genera log. Raccomando e consiglio di impostare la registrazione al massimo. Leggere i log aumenterà le tue possibilità di lavorare correttamente con l'ORM.
  11. hibernate.jdbc.batch_size — Dimensione massima del batch.
  12. hibernate.jdbc.fetch_size — Dimensione massima di recupero.
  13. hibernate.order_inserts - consente inserimenti dinamici.
  14. hibernate.order_updates - Consente aggiornamenti dinamici.
  15. hibernate.jdbc.batch_versioned_data: consente l'invio in batch. Guarda il tuo DBMS: non tutti lo supportano.
  16. classe di mappatura: classi che sono le nostre entità. Tutto deve essere elencato.
  1. Ora la nostra essenza deve essere determinata. Possiamo verificarlo nella scheda Persistenza:

    Entità JPA e relazioni DB - 11

    Risultato:

    Entità JPA e relazioni DB - 12
  2. Dobbiamo anche configurare i dati di assegnazione:

    Entità JPA e relazioni DB - 13 Entità JPA e relazioni DB - 14

    Risultati: abbiamo eseguito la mappatura uno-a-uno. Il materiale è solo a scopo informativo, i dettagli sono nei riferimenti.

Relazione uno-a-molti

Link alla filiale qui . Non pubblicherò più il codice nell'articolo, poiché è già troppo lungo. Guardiamo tutto il codice su GitHub.
  1. Come risultato dell'esecuzione dello script di inizializzazione, otteniamo quanto segue:

    Entità JPA e relazioni DB - 15

    Senti la differenza con la tabella precedente?

  2. Diagramma:

    Entità JPA e relazioni DB - 16

    Relazione uno a molti: un autore può avere più libri. L'entità di sinistra corrisponde ad una o più entità di destra.

  3. La differenza nella mappatura sarà nelle annotazioni e nei campi:

    Viene visualizzato un campo nella classe Autore :

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

    È già un set, poiché possiamo avere diversi libri. @OneToMany parla del tipo di atteggiamento. FetchType.Lazy dice che non è necessario caricare l'intero elenco di libri se non è specificato nella richiesta. Va anche detto che questo campo NON PUÒ essere aggiunto a toString, altrimenti inizieremo a fumare uno StackOverflowError. La mia amata Lombok si occupa di questo:

    @ToString(exclude = "books")

    Nella classe Libro eseguiamo feedback molti-a-uno:

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

    Qui concludiamo che Uno-a-molti è l'immagine speculare di Molti-a-uno e viceversa. Va sottolineato che Hibernate non sa nulla delle comunicazioni bidirezionali. Per lui si tratta di due collegamenti diversi: uno in una direzione, l'altro nella direzione opposta.

  4. Non è cambiato molto in hibernate.cfg.xml .

  5. Persistenza:

    Entità JPA e relazioni DB - 17

Relazione molti-a-uno

Poiché Many-to-One è un'immagine speculare di One-to-Many, ci saranno poche differenze. Link alla filiale qui .
  1. Come risultato dell'esecuzione dello script di inizializzazione, otteniamo il seguente risultato:

    Entità JPA e relazioni DB - 18
  2. Diagramma:

    Entità JPA e relazioni DB - 19
  3. La differenza nella mappatura sarà nelle annotazioni e nei campi:

    Non esiste più un set nella classe Author , poiché è stato spostato nella classe Book .

  4. hibernate.cfg.xml

  5. Persistenza:

    Entità JPA e relazioni DB - 20

Relazione molti-a-molti

Passiamo alla relazione più interessante. Questo rapporto, secondo tutte le regole della decenza e dell'indecenza, viene creato attraverso un tavolo aggiuntivo. Ma questa tabella non è un'entità. Interessante, vero? Diamo un'occhiata a questa merda. Link alla filiale qui .
  1. Guarda lo script di inizializzazione , qui appare una tabella HAS aggiuntiva. Otteniamo qualcosa come l'autore-ha-libro.

    Come risultato dell'esecuzione dello script, otterremo le seguenti tabelle:

    Entità JPA e relazioni DB - 21
  2. Diagramma:

    Entità JPA e relazioni DB - 22

    Nel nostro esempio risulta che un libro può avere molti autori e un autore può avere molti libri. Potrebbero sovrapporsi.

  3. Le classi di mappatura avranno insiemi all'interno delle classi. Ma come ho detto, la tabella HAS non è un'entità.

    Classe dell'autore :

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

    @ManyToMany è un tipo di relazione.

    @JoinTable : questo è esattamente ciò che collegherà l'attributo con una tabella HAS aggiuntiva. In esso specifichiamo due attributi che punteranno alle chiavi primarie di due entità.

    Lezione di libro :

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

    Qui indichiamo FetchType e il campo che utilizzeremo per mappare.

  4. Il nostro hibernate.cfg.xml è rimasto nuovamente invariato (non prendo in considerazione il fatto che abbiamo creato un nuovo DB per ogni ramo).

  5. Persistenza:

    Entità JPA e relazioni DB - 23

Debriefing

Quindi, abbiamo esaminato superficialmente i tipi di relazioni DB e abbiamo capito come implementarle nel modello ORM. Abbiamo scritto un progetto di test che dimostra tutte le connessioni e abbiamo capito come configurare hibernate/jpa. Uff.

link utili

I miei articoli precedenti: PS Potrebbero esserci errori e mancanze nel testo. PPS L'autore stava fumando qualcosa di strano mentre scriveva questo articolo. Grazie per l'attenzione!
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION