JavaRush /Java Blog /Random-JA /JPA エンティティと DB の関係
Nikita Koliadin
レベル 40
Днепр

JPA エンティティと DB の関係

Random-JA グループに公開済み

JPA エンティティと DB の関係

同僚の皆さん、こんにちは!
JPA エンティティと DB の関係 - 1
この資料は、データベース (以下、単にDB - 「データベース」)の構成をすでに理解しており、オブジェクト リレーショナル マッピング (以下、単にORM ) の仕組みとその実装 ( Hibernate / JPAなど) についての最小限の知識をすでに持っている人を対象としています。。これに慣れていない場合は、 JDBCから始めて、それから ORM モデルに進むことをお勧めします。警告しましたが、適切な準備なしでこの記事を読んだ後のあなたの精神については責任を負いません。:) すべてを順番に処理してみましょう。まず、理論を少しだけ掘り下げてみましょう。次に、みんなが大好きな Java でこのようなことを行う方法を見つけます。また、プロジェクトのチートシートも作成します。これは、トピックの理解を強化し、どのようにマッピングを行うべきかのテンプレートとして機能します。じゃあ、やってみよう!

エンティティとは何ですか?

エンティティは、属性 (ドア、車輪、エンジン) を持つ現実世界のオブジェクト (車など)です。DB エンティティ: この場合、エンティティは DB に保存されており、すべてが単純です。車をデータベースに登録する理由と方法については、後ほど説明します。

DBリレーションシップとは何ですか?

遠い昔、遠い王国でリレーショナル DB が作成されました。この DB では、データはテーブルの形式で表示されます。しかし、シュレックのロバも、これらのテーブルを相互接続するメカニズムを作成する必要があることを理解していました。その結果、4 つの DB関係が表示されました。
  1. 1対1
  2. 1対多
  3. 多対一
  4. 多対多
このすべてを初めて見た場合は、もう一度警告します。状況はさらに悪化します。散歩に行くことを考えてください。例を使用してこれらすべての関係を分析し、それらの違いを理解します。

ホラーの例

5 つのブランチを持つ 1 つのプロジェクトがあります。プロジェクトの説明が含まれるマスターと、DB 関係ごとに 1 つのブランチです。各ブランチには、DB を作成してテスト データを入力するための SQL スクリプトと、アノテーション マッピングを備えたエンティティ クラスが含まれます。各ブランチに Hibernate 構成ファイルもあります。クラウド DB や外部 DB の個々の側面に気を取られないよう、プロジェクトにはH2組み込み DBを使用します。リンクに従って、掃除機に H2 DB をインストールします。1 つのブランチで各ステップを説明します。残りは重要なポイントだけです。最後にまとめていきます。行く。 これは私のプロジェクトのマスター ブランチへのリンクです。

1対1の関係

ここのブランチへのリンク。
  1. H2 DB をプロジェクトに接続する必要があります。ここで強調しておきたいのは、DB などを快適に操作するには Ultimate IDEA が必要であるということです。すでに持っている場合は、DB 接続に直接移動します。[データベース] タブに移動し、スクリーンショットのように操作します。

    JPA エンティティと DB の関係 - 2

    次にDBの設定に移ります。データを入力することも、DBMS を入力することもできます。繰り返しますが、簡単にするために H2 DB を使用します。

    JPA エンティティと DB の関係 - 3

    次に回路を組み立ててみましょう。この手順はオプションですが、DB に複数のスキーマがある場合にお勧めします。

    JPA エンティティと DB の関係 - 4

    設定を適用すると、最終的には次のような結果が得られるはずです。

    JPA エンティティと DB の関係 - 5
  2. データベースを作成し、IDEA からデータベースへのアクセスを構成しました。次に、その中にテーブルを作成し、データを入力する必要があります。たとえば、Author と Book という 2 つのエンティティを取り上げます。本には、一人の著者がいる場合もあれば、複数の著者がいる場合もあれば、一人の著者がいない場合もあります。この例では、すべての種類の接続を作成します。しかし、この時点では 1 対 1 の関係です。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)
    );

    そしてそれを実行しましょう:

    JPA エンティティと DB の関係 - 6

    コンソールでの実行結果:

    JPA エンティティと DB の関係 - 7

    DB の結果:

    JPA エンティティと DB の関係 - 8
  3. テーブルの図を見てみましょう。これを行うには、DB で RMB を実行します。

    JPA エンティティと DB の関係 - 9

    結果:

    JPA エンティティと DB の関係 - 10

    UML図では、すべての主キーと外部キーが表示され、テーブル間の接続も表示されます。

  4. DB にテスト データを埋めるスクリプトを書いてみましょう。

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

    つまり、何が起こるのでしょうか?1 対 1 の関係は、あるテーブルのエンティティが別のテーブルのエンティティに関連付けられている場合 (または、BOOK_ID から NOT NULL が削除されている場合はまったく関連付けられていない場合) に必要です。この例では、1 つの本には 1 人の著者がいる必要があります。他に方法はありません。

  5. ここで最も興味深いのは、Java クラスを DB エンティティに接続する方法です。とてもシンプルです。Book と Author という 2 つのクラスを作成しましょう。例を使用して、クラス 1 と主要な通信分野を分析します。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;
    }
順番に考えてみましょう。
  1. クラス内のすべてのフィールドは、DB エンティティの属性を繰り返します。
  2. @Data ( Lombokから) は、各フィールドに対してゲッターとセッターが作成され、等しい、ハッシュコードがオーバーライドされ、toString メソッドが生成されると述べています。
  3. @Entity は、指定されたクラスがエンティティであり、DB エンティティに関連付けられていることを示します。
  4. @DynamicInsert@DynamicUpdate は、DB 内で動的挿入と更新が実行されることを示します。これらは、正しいバッチ処理を行うために役立つ、より深い Hibernate 設定です。
  5. @Table (name = "AUTHOR") は、Book クラスを DB AUTHOR テーブルにバインドします。
  6. @Id は、このフィールドが主キーであることを示しています。
  7. @GeneratedValue (strategy = GenerationType.IDENTITY) – 主キー生成戦略。
  8. @Column (name = "ID"、nullable = false) はフィールドを DB 属性に関連付け、指定された DB フィールドを null にすることはできないことも示します。これは、エンティティからテーブルを生成する場合にも役立ちます。今プロジェクトを作成する方法とは逆のプロセスです。これは単体テストのテスト DB で必要です。
  9. @OneToOne は、指定されたフィールドが 1 対 1 の関係フィールドであることを示しています。
  10. @JoinColumn (name = "BOOK_ID"、unique = true、nullable = false) - BOOK_ID 列が作成されます。これは一意であり、null ではありません。
反対側 ( Bookクラス内) では、1 対 1 接続を作成し、マッピングが行われるフィールドを指定する必要もあります。@OneToOne(mappedBy = "book") - この例では、これは Author クラスの book フィールドです。JPA が自らリンクします。一見、ごちゃごちゃと注釈が入っているように見えますが、実はとても便利で、慣れてくると何も考えずに自動的に注釈が追加されるようになります。
  1. 次に、Hibernate を設定しましょう。これを行うには、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>
プロパティの説明:
  1. hibernate.dialect は、選択した DBMS の方言です。
  2. hibernate.connection.driver_class - DB のドライバー クラス。
  3. hibernate.connection.url - DB の utl。DB を構成した最初のポイントから取得できます。
  4. hibernate.connection.username - DB ユーザー名。
  5. hibernate.connection.password — DB ユーザーのパスワード。
  6. hibernate.hbm2ddl.auto - テーブル生成のセットアップ。更新する場合、すでに作成されている場合は生成されず、更新されるだけです。
  7. hibernate.show_sql - DB クエリを表示するかどうか。
  8. hibernate.format_sql - DB クエリをフォーマットするかどうか。そうでない場合は、すべて 1 行に表示されます。オンにすることをお勧めします。
  9. hibernate.use_sql_comments - DB クエリにコメントします。これが挿入の場合、リクエストが挿入タイプであることを示すコメントがリクエストの上に書き込まれます。
  10. hibernate.generate_statistics - ログを生成します。ログ記録を最大に設定することをお勧めします。ログを読むと、ORM を正しく操作できる可能性が高くなります。
  11. hibernate.jdbc.batch_size — 最大バッチ サイズ。
  12. hibernate.jdbc.fetch_size — 最大フェッチ サイズ。
  13. hibernate.order_inserts - 動的挿入を許可します。
  14. hibernate.order_updates - 動的更新を許可します。
  15. hibernate.jdbc.batch_versioned_data - バッチ処理を許可します。DBMS を見てください。誰もがこれをサポートしているわけではありません。
  16. マッピング クラス - エンティティであるクラス。すべてをリストする必要があります。
  1. 今、私たちの本質を決定しなければなりません。これは「永続化」タブで確認できます。

    JPA エンティティと DB の関係 - 11

    結果:

    JPA エンティティと DB の関係 - 12
  2. データの割り当ても設定する必要があります。

    JPA エンティティと DB の関係 - 13 JPA エンティティと DB の関係 - 14

    結果: 1 対 1 のマッピングが完了しました。この資料は情報提供のみを目的としており、詳細は参考文献に記載されています。

1対多の関係

ここのブランチへのリンク。すでに長くなってしまったので、記事にはコードを掲載しません。GitHub 上のすべてのコードを確認します。
  1. 初期化スクリプトを実行した結果、次の結果が得られます。

    JPA エンティティと DB の関係 - 15

    前の表との違いを感じますか?

  2. 図:

    JPA エンティティと DB の関係 - 16

    1 対多の関係 - 1 人の著者が複数の本を持つことができます。左側のエンティティは 1 つ以上の右側のエンティティに対応します。

  3. マッピングの違いは、注釈とフィールドにあります。

    Authorクラスにフィールドが表示されます。

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

    何冊でもいけるのでもうセットになっています。@OneToManyは態度のタイプについて話しています。FetchType.Lazy は、リクエストで指定されていない場合、書籍のリスト全体をロードする必要がないことを示しています。また、このフィールドを toString に追加することはできません。追加しないと、StackOverflowError が発生します。私の愛するロンボク島がこれを担当します。

    @ToString(exclude = "books")

    Bookクラスでは、多対 1 のフィードバックを行います。

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

    ここで、1 対多は多対 1 の鏡像であり、その逆も同様であると結論付けます。Hibernate は双方向通信について何も知らないことを強調しておく必要があります。彼にとって、これらは 2 つの異なる接続です。1 つは一方向で、もう 1 つは反対方向です。

  4. hibernate.cfg.xmlには大きな変更はありません。

  5. 永続性:

    JPA エンティティと DB の関係 - 17

多対一の関係

多対一は一対多の鏡像であるため、違いはほとんどありません。ここのブランチへのリンク。
  1. 初期化スクリプトを実行した結果、次の結果が得られます。

    JPA エンティティと DB の関係 - 18
  2. 図:

    JPA エンティティと DB の関係 - 19
  3. マッピングの違いは、注釈とフィールドにあります。

    AuthorクラスにはBookクラスに移動したため、セットは存在しません。

  4. hibernate.cfg.xml

  5. 永続性:

    JPA エンティティと DB の関係 - 20

多対多の関係

最も興味深い関係に移りましょう。この関係は、良識と猥褻のすべての規則に従って、追加のテーブルを通じて作成されます。しかし、このテーブルはエンティティではありません。興味深いですよね?このたわごとを見てみましょう。ここのブランチへのリンク。
  1. 初期化スクリプトを確認すると、追加の HAS テーブルがここに表示されます。著者所有の本のようなものを入手します。

    スクリプトを実行した結果、次のテーブルが取得されます。

    JPA エンティティと DB の関係 - 21
  2. 図:

    JPA エンティティと DB の関係 - 22

    この例では、1 つの本に多数の著者が存在する可能性があり、1 人の著者が多数の本を存在できることがわかります。それらは重複する場合があります。

  3. マッピング クラスはクラス内にセットを持ちます。しかし、先ほども述べたように、HAS テーブルはエンティティではありません。

    著者クラス:

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

    @ManyToManyは関係の一種です。

    @JoinTable - これはまさに属性を追加の HAS テーブルに接続するものです。その中で、2 つのエンティティの主キーを指す 2 つの属性を指定します。

    書籍クラス:

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

    ここでは、FetchType とマッピングに使用するフィールドを示します。

  4. hibernate.cfg.xml変更されませんでした (ブランチごとに新しい DB を作成したという事実は考慮していません)。

  5. 永続性:

    JPA エンティティと DB の関係 - 23

報告会

そこで、DB 関係の種類を表面的に調べ、それらを ORM モデルに実装する方法を見つけました。私たちはすべての接続を示すテスト プロジェクトを作成し、hibernate / jpa の設定方法を見つけました。ふー。

役立つリンク

私の以前の記事: PS 本文中に間違いや不足があるかもしれません。PPS この記事を書いている間、著者は奇妙なものを吸っていました。ご清聴ありがとうございました!
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION