JavaRush /Java-Blog /Random-DE /JPA-Entitäten und DB-Beziehungen
Nikita Koliadin
Level 40
Днепр

JPA-Entitäten und DB-Beziehungen

Veröffentlicht in der Gruppe Random-DE

JPA-Entitäten und DB-Beziehungen

Guten Tag, Kollegen!
JPA-Entitäten und DB-Beziehungen – 1
Dieses Material richtet sich an diejenigen, die bereits über Kenntnisse in der Organisation von Datenbanken (im Folgenden einfach DB – „Datenbank“), minimale Kenntnisse über die Funktionsweise von objektrelationalem Mapping (im Folgenden einfach ORM ) und deren Implementierungen wie Hibernate/JPA verfügen . Wenn Sie damit nicht vertraut sind, empfehle ich Ihnen, mit JDBC zu beginnen und erst dann zum ORM-Modell überzugehen. Ich habe Sie gewarnt und übernehme keine Verantwortung für Ihre Psyche, nachdem Sie diesen Artikel ohne entsprechende Vorbereitung gelesen haben! :) Fangen wir an, alles der Reihe nach zu erledigen. Zunächst werden wir uns ein wenig mit der Theorie befassen, nur ein wenig. Zweitens werden wir herausfinden, wie man diesen Mist in jedermanns Lieblings-Java macht. Außerdem verfassen wir gemeinsam mit Ihnen einen Projekt-Spickzettel, der unser Verständnis des Themas festigt und als Vorlage dafür dient, WIE das Mapping durchgeführt werden sollte . Also machen wir's!

Was ist Entität?

Eine Entität ist ein Objekt aus dem wirklichen Leben (z. B. ein Auto), das über Attribute (Türen, RÄDER , Motor) verfügt. DB-Entität: In diesem Fall wird unsere Entität in einer Datenbank gespeichert, alles ist einfach. Warum und wie wir das Auto in die Datenbank aufgenommen haben – das schauen wir uns später an.

Was sind DB-Beziehungen?

Vor langer Zeit wurde im fernen Königreich eine relationale Datenbank erstellt . In dieser Datenbank wurden die Daten in Tabellenform dargestellt. Aber selbst der Esel aus Shrek verstand, dass es notwendig war, einen Mechanismus zur Verbindung dieser Tische zu schaffen. Als Ergebnis erschienen 4 DB- Beziehungen :
  1. Eins zu eins
  2. Eins-zu-Viele
  3. Viele-zu-eins
  4. Viel zu viel
Wenn Sie das alles zum ersten Mal sehen, warne ich Sie noch einmal – es wird noch schlimmer: Denken Sie an einen Spaziergang. Wir werden alle diese Zusammenhänge anhand eines Beispiels analysieren und den Unterschied zwischen ihnen verstehen.

Horrorbeispiel

Wir werden ein Projekt haben, das 5 Zweige haben wird: Master, wo es eine Beschreibung des Projekts geben wird, und 1 Zweig für jede DB-Beziehung. Jeder Zweig enthält SQL-Skripte zum Erstellen einer Datenbank und zum Füllen dieser mit Testdaten sowie eine Entity-Klasse mit Annotation-Mapping. Für jeden Zweig wird es außerdem eine Hibernate-Konfigurationsdatei geben. Ich werde für das Projekt die eingebettete H2- Datenbank verwenden, um nicht von einzelnen Aspekten der Cloud-Datenbank oder der externen Datenbank abgelenkt zu werden. Wenn Sie dem Link folgen, installieren Sie H2 DB auf Ihrem Staubsauger. Ich werde jeden Schritt in einem Zweig beschreiben, der Rest sind nur die wichtigsten Punkte. Am Ende fassen wir zusammen. Gehen. Dies ist ein Link zum Master-Zweig meines Projekts.

Eins-zu-Eins-Beziehung

Link zur Filiale hier .
  1. Wir müssen H2 DB mit unserem Projekt verbinden. Hier müssen wir betonen, dass wir Ultimate IDEA benötigen, um bequem mit DB und anderen Dingen arbeiten zu können. Wenn Sie es bereits haben, dann gehen Sie direkt zur DB-Verbindung. Gehen Sie zur Registerkarte „Datenbank“ und gehen Sie wie im Screenshot vor:

    JPA-Entitäten und DB-Beziehungen – 2

    Als nächstes gehen wir zu den DB-Einstellungen über. Sie können Ihre Daten und sogar Ihr DBMS eingeben; ich wiederhole, ich verwende der Einfachheit halber H2 DB.

    JPA-Entitäten und DB-Beziehungen – 3

    Als nächstes bauen wir die Schaltung auf. Dieser Schritt ist optional, wird jedoch empfohlen, wenn Sie mehrere Schemata in der Datenbank haben.

    JPA-Entitäten und DB-Beziehungen – 4

    Übernehmen Sie die Einstellungen und am Ende sollten wir etwa Folgendes erhalten:

    JPA-Entitäten und DB-Beziehungen – 5
  2. Wir haben die Datenbank erstellt und den Zugriff darauf von IDEA aus konfiguriert. Jetzt müssen Sie darin Tabellen erstellen und diese mit einigen Daten füllen. Ich nehme zum Beispiel zwei Entitäten: Autor und Buch. Ein Buch kann einen Autor haben, es kann mehrere Autoren haben oder auch keinen. In diesem Beispiel erstellen wir alle Arten von Verbindungen. Aber an diesem Punkt - Eins-zu-Eins-Beziehung. Lassen Sie uns das entsprechende Skript erstellen, das DB-Tabellen erstellt :

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

    Und lass es uns ausführen:

    JPA-Entitäten und DB-Beziehungen – 6

    Ausführungsergebnis in der Konsole:

    JPA-Entitäten und DB-Beziehungen – 7

    Ergebnis in der DB:

    JPA-Entitäten und DB-Beziehungen – 8
  3. Schauen wir uns ein Diagramm unserer Tabellen an. Um dies zu tun, RMB auf unserer DB:

    JPA-Entitäten und DB-Beziehungen – 9

    Ergebnis:

    JPA-Entitäten und DB-Beziehungen – 10

    Im UML- Diagramm können wir alle Primärschlüssel und Fremdschlüssel sehen, außerdem sehen wir die Verbindung zwischen unseren Tabellen.

  4. Schreiben wir ein Skript, das unsere Datenbank mit Testdaten füllt:

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

    Ich meine, was passiert? Eine Eins-zu-Eins-Beziehung ist erforderlich, wenn die Entität einer Tabelle mit einer Entität einer anderen verknüpft ist (oder überhaupt nicht verknüpft ist, wenn NOT NULL aus BOOK_ID entfernt wird). In unserem Beispiel MUSS ein Buch einen Autor haben. Kein anderer Weg.

  5. Das Interessanteste ist nun, wie man eine Java-Klasse mit DB-Entitäten verbindet. Sehr einfach. Lassen Sie uns zwei Klassen „Buch“ und „Autor“ erstellen. Anhand eines Beispiels analysiere ich die Klasse 1 und die wichtigsten Kommunikationsfelder. Nehmen wir als Beispiel die Author- Klasse :

    @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;
    }
Lassen Sie es uns der Reihe nach herausfinden:
  1. Alle Felder in der Klasse wiederholen die Attribute der DB-Entität.
  2. @Data (von Lombok ) besagt, dass für jedes Feld ein Getter und ein Setter erstellt werden, gleich, Hashcode überschrieben wird und eine toString-Methode generiert wird.
  3. @Entity besagt, dass die angegebene Klasse eine Entität ist und einer DB-Entität zugeordnet ist.
  4. @DynamicInsert und @DynamicUpdate sagen, dass dynamische Einfügungen und Aktualisierungen in der Datenbank durchgeführt werden. Dabei handelt es sich um tiefergehende Einstellungen für den Ruhezustand, die für Sie nützlich sein werden, damit Sie die RICHTIGE Stapelverarbeitung erhalten.
  5. @Table (name = „AUTHOR“) bindet die Book-Klasse an die DB-AUTHOR-Tabelle.
  6. @Id sagt, dass dieses Feld der Primärschlüssel ist.
  7. @GeneratedValue (strategy = GenerationType.IDENTITY) – Strategie zur Primärschlüsselgenerierung.
  8. @Column (name = „ID“, nullable = false) verknüpft ein Feld mit einem DB-Attribut und sagt außerdem, dass das angegebene DB-Feld nicht null sein darf. Dies ist auch nützlich, wenn Tabellen aus Entitäten generiert werden. Der umgekehrte Vorgang zu dem, wie wir jetzt unser Projekt erstellen. Dies wird in den Test-DBs für Unit-Tests benötigt.
  9. @OneToOne sagt, dass das angegebene Feld ein Eins-zu-Eins-Beziehungsfeld ist.
  10. @JoinColumn (name = „BOOK_ID“, unique = true, nullable = false) – es wird eine BOOK_ID-Spalte erstellt, die eindeutig und nicht null ist.
Auf der Rückseite (in der Book- Klasse ) müssen wir auch eine Eins-zu-Eins-Verbindung herstellen und das Feld angeben, auf dem die Zuordnung erfolgt. @OneToOne(mappedBy = "book") – in diesem Beispiel ist dies das Buchfeld der Author-Klasse. JPA wird sie selbst verlinken. Auf den ersten Blick mag es so aussehen, als gäbe es ein Durcheinander an Anmerkungen, aber in Wirklichkeit ist es sehr praktisch und mit etwas Erfahrung werden Sie sie automatisch hinzufügen, ohne darüber nachzudenken.
  1. Jetzt konfigurieren wir den Ruhezustand. Erstellen Sie dazu eine Datei 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>
Beschreibung der Eigenschaften :
  1. hibernate.dialect ist der Dialekt des von uns gewählten DBMS.
  2. hibernate.connection.driver_class – Treiberklasse unserer Datenbank.
  3. hibernate.connection.url – UTL unserer Datenbank. Sie können es vom ersten Punkt an übernehmen, an dem wir die Datenbank konfiguriert haben.
  4. hibernate.connection.username – DB-Benutzername.
  5. hibernate.connection.password – DB-Benutzerpasswort.
  6. hibernate.hbm2ddl.auto – Einrichten der Tabellengenerierung. Bei Aktualisierung wird nicht generiert, ob es bereits erstellt wurde, sondern nur aktualisiert.
  7. hibernate.show_sql – ob DB-Abfragen angezeigt werden sollen.
  8. hibernate.format_sql – ob DB-Abfragen formatiert werden sollen. Wenn nicht, stehen sie alle in einer Zeile. Ich empfehle, es einzuschalten.
  9. hibernate.use_sql_comments – kommentiert DB-Abfragen. Wenn es sich um eine Einfügung handelt, wird über der Anfrage ein Kommentar geschrieben, dass die Anfrage vom Typ Einfügung ist.
  10. hibernate.generate_statistics – generiert Protokolle. Ich empfehle und empfehle, die Protokollierung auf das Maximum einzustellen. Das Lesen der Protokolle erhöht Ihre Chancen, korrekt mit dem ORM zu arbeiten.
  11. hibernate.jdbc.batch_size – Maximale Batchgröße.
  12. hibernate.jdbc.fetch_size – Maximale Abrufgröße.
  13. hibernate.order_inserts – ermöglicht dynamische Einfügungen.
  14. hibernate.order_updates – Ermöglicht dynamische Updates.
  15. hibernate.jdbc.batch_versioned_data – ermöglicht Batchverarbeitung. Schauen Sie sich Ihr DBMS an: Nicht jeder unterstützt dies.
  16. Zuordnungsklasse – Klassen, die unsere Entitäten sind. Alles muss aufgelistet werden.
  1. Jetzt muss unser Wesen bestimmt werden. Wir können dies auf der Registerkarte „Persistenz“ überprüfen:

    JPA-Entitäten und DB-Beziehungen – 11

    Ergebnis:

    JPA-Entitäten und DB-Beziehungen – 12
  2. Wir müssen auch die Zuweisungsdaten konfigurieren:

    JPA-Entitäten und DB-Beziehungen – 13 JPA-Entitäten und DB-Beziehungen – 14

    Ergebnisse: Wir haben eine Eins-zu-Eins-Zuordnung durchgeführt. Das Material dient nur zu Informationszwecken, Einzelheiten finden Sie in den Referenzen.

Eins-zu-viele-Beziehung

Link zur Filiale hier . Ich werde den Code nicht mehr im Artikel veröffentlichen, da er bereits zu lang ist. Wir schauen uns den gesamten Code auf GitHub an.
  1. Als Ergebnis der Ausführung des Initialisierungsskripts erhalten wir Folgendes:

    JPA-Entitäten und DB-Beziehungen – 15

    Spüren Sie den Unterschied zur vorherigen Tabelle?

  2. Diagramm:

    JPA-Entitäten und DB-Beziehungen – 16

    One-to-Many-Beziehung – ein Autor kann mehrere Bücher haben. Die linke Entität entspricht einer oder mehreren rechten.

  3. Der Unterschied bei der Zuordnung liegt in den Anmerkungen und Feldern:

    In der Author -Klasse erscheint ein Feld:

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

    Es ist bereits ein Set, da wir mehrere Bücher haben können. @OneToMany spricht über den Einstellungstyp. FetchType.Lazy sagt, dass wir nicht die gesamte Bücherliste laden müssen, wenn sie nicht in der Anfrage angegeben ist. Es sollte auch gesagt werden, dass dieses Feld NICHT zu toString hinzugefügt werden kann, sonst fangen wir an, einen StackOverflowError auszulösen. Dafür sorgt mein geliebter Lombok:

    @ToString(exclude = "books")

    Im Buchkurs führen wir ein Many-to-One-Feedback durch:

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

    Hier kommen wir zu dem Schluss, dass One-to-Many das Spiegelbild von Many-to-One ist und umgekehrt. Es sollte betont werden, dass Hibernate nichts über bidirektionale Kommunikation weiß. Für ihn sind das zwei unterschiedliche Verbindungen: eine in die eine Richtung, die andere in die entgegengesetzte Richtung.

  4. An hibernate.cfg.xml hat sich nicht viel geändert .

  5. Beharrlichkeit:

    JPA-Entitäten und DB-Beziehungen – 17

Viele-zu-eins-Beziehung

Da Many-to-One ein Spiegelbild von One-to-Many ist, wird es kaum Unterschiede geben. Link zur Filiale hier .
  1. Als Ergebnis der Ausführung des Initialisierungsskripts erhalten wir das folgende Ergebnis:

    JPA-Entitäten und DB-Beziehungen – 18
  2. Diagramm:

    JPA-Entitäten und DB-Beziehungen – 19
  3. Der Unterschied bei der Zuordnung liegt in den Anmerkungen und Feldern:

    Es gibt keinen Satz mehr in der Klasse „Autor“ , da er in die Klasse „Buch“ verschoben wurde .

  4. hibernate.cfg.xml

  5. Beharrlichkeit:

    JPA-Entitäten und DB-Beziehungen – 20

Viele-zu-viele-Beziehung

Kommen wir zur interessantesten Beziehung. Diese Beziehung wird nach allen Regeln des Anstands und der Unanständigkeit durch eine zusätzliche Tabelle hergestellt. Aber dieser Tisch ist keine Einheit. Interessant, oder? Werfen wir einen Blick auf diesen Scheiß. Link zur Filiale hier .
  1. Schauen Sie sich das Initialisierungsskript an . Hier erscheint eine zusätzliche HAS-Tabelle. Wir bekommen so etwas wie „Autor-hat-Buch“.

    Als Ergebnis der Ausführung des Skripts erhalten wir die folgenden Tabellen:

    JPA-Entitäten und DB-Beziehungen – 21
  2. Diagramm:

    JPA-Entitäten und DB-Beziehungen – 22

    In unserem Beispiel stellt sich heraus, dass ein Buch viele Autoren haben kann und ein Autor viele Bücher haben kann. Sie können sich überschneiden.

  3. Zuordnungsklassen haben Sätze innerhalb von Klassen. Aber wie gesagt, die HAS-Tabelle ist keine Einheit.

    Autorenklasse : _

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

    @ManyToMany ist eine Art Beziehung.

    @JoinTable – genau das verbindet das Attribut mit einer zusätzlichen HAS-Tabelle. Darin geben wir zwei Attribute an, die auf die Primärschlüssel zweier Entitäten verweisen.

    Buchklasse : _

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

    Hier geben wir FetchType und das Feld an, das wir für die Zuordnung verwenden werden.

  4. Unsere hibernate.cfg.xml blieb wieder unverändert (ich berücksichtige nicht, dass wir für jeden Zweig eine neue Datenbank erstellt haben).

  5. Beharrlichkeit:

    JPA-Entitäten und DB-Beziehungen – 23

Nachbesprechung

Daher haben wir die Arten von DB-Beziehungen oberflächlich untersucht und herausgefunden, wie man sie im ORM-Modell implementiert. Wir haben ein Testprojekt geschrieben, das alle Verbindungen demonstriert, und herausgefunden, wie man Hibernate/JPA konfiguriert. Puh.

Nützliche Links

Meine vorherigen Artikel: PS: Der Text kann Fehler und Unzulänglichkeiten enthalten. PPS Der Autor hat beim Schreiben dieses Artikels etwas Seltsames geraucht. Vielen Dank für Ihre Aufmerksamkeit!
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION