JavaRush /Blog Java /Random-VI /Các thực thể JPA và các mối quan hệ DB
Nikita Koliadin
Mức độ
Днепр

Các thực thể JPA và các mối quan hệ DB

Xuất bản trong nhóm

Thực thể JPA && Mối quan hệ DB

Chúc một ngày tốt lành, đồng nghiệp!
Các thực thể JPA và các mối quan hệ DB - 1
Tài liệu này dành cho những người đã hiểu biết về tổ chức cơ sở dữ liệu (sau đây gọi đơn giản là DB - "Cơ sở dữ liệu"), kiến ​​thức tối thiểu về cách hoạt động của Ánh xạ quan hệ đối tượng (sau đây gọi đơn giản là ORM ) và các triển khai của nó, chẳng hạn như Hibernate / JPA . Nếu bạn không quen với điều này, tôi khuyên bạn nên bắt đầu với JDBC và chỉ sau đó chuyển sang mô hình ORM. Tôi đã cảnh báo bạn và tôi không chịu trách nhiệm về tâm lý của bạn sau khi đọc bài viết này mà không có sự chuẩn bị thích hợp! :) Hãy bắt đầu giải quyết mọi thứ theo thứ tự. Đầu tiên chúng ta sẽ đi sâu một chút về lý thuyết, chỉ một chút thôi. Thứ hai, chúng ta sẽ tìm ra cách thực hiện điều này bằng ngôn ngữ Java yêu thích của mọi người. Chúng tôi cũng sẽ viết cho bạn một bảng tóm tắt dự án, bảng này sẽ củng cố sự hiểu biết của chúng tôi về chủ đề này và dùng làm mẫu cho việc lập bản đồ CÁCH thực hiện . Vì vậy, hãy làm điều đó!

Thực thể là gì?

Thực thể một đối tượng có trong đời thực (ví dụ: ô tô) có các thuộc tính (cửa, BÁNH XE , động cơ). Thực thể DB: Trong trường hợp này, thực thể của chúng tôi được lưu trữ trong DB, mọi thứ đều đơn giản. Tại sao và làm thế nào chúng ta đưa chiếc xe vào cơ sở dữ liệu - chúng ta sẽ xem xét nó sau.

Mối quan hệ DB là gì?

Cách đây rất lâu, ở vương quốc xa xôi , một DB quan hệ đã được tạo ra . Trong DB này, dữ liệu được trình bày dưới dạng bảng. Nhưng ngay cả con lừa của Shrek cũng hiểu rằng cần phải tạo ra một cơ chế kết nối các bảng này với nhau. Kết quả xuất hiện 4 mối quan hệ DB :
  1. Một-một
  2. Một-nhiều
  3. Nhiều-một
  4. Nhiều nhiều
Nếu bạn nhìn thấy tất cả những điều này lần đầu tiên, tôi cảnh báo bạn một lần nữa - mọi chuyện sẽ trở nên tồi tệ hơn: hãy nghĩ đến việc đi dạo. Chúng tôi sẽ phân tích tất cả các mối quan hệ này bằng một ví dụ và hiểu sự khác biệt giữa chúng.

Ví dụ kinh dị

Chúng ta sẽ có một dự án có 5 nhánh: master, nơi sẽ có mô tả về dự án và 1 nhánh cho mỗi mối quan hệ DB. Mỗi nhánh sẽ chứa các tập lệnh SQL để tạo một DB và điền dữ liệu thử nghiệm vào đó, cùng với một lớp Thực thể có ánh xạ chú thích. Cũng sẽ có một tệp cấu hình Hibernate cho mỗi nhánh. Tôi sẽ sử dụng DB nhúng H2 cho dự án để không bị phân tâm bởi các khía cạnh riêng lẻ của DB đám mây hoặc DB bên ngoài. Bằng cách nhấp vào liên kết, hãy cài đặt H2 DB trên máy hút bụi của bạn. Mình sẽ mô tả từng bước theo 1 nhánh, còn lại chỉ là những điểm chính thôi. Cuối cùng chúng tôi sẽ tóm tắt. Đi. Đây là liên kết đến nhánh chính của dự án của tôi.

Mối quan hệ một-một

Liên kết đến chi nhánh ở đây .
  1. Chúng ta cần kết nối H2 DB với dự án của mình. Ở đây chúng tôi cần nhấn mạnh rằng chúng tôi cần Ultimate IDEA để làm việc thoải mái với DB và những thứ khác. Nếu bạn đã có nó rồi thì hãy truy cập trực tiếp vào kết nối DB. Chuyển đến tab Cơ sở dữ liệu và thực hiện như trong ảnh chụp màn hình:

    JPA Entities and DB Relationships - 2

    Tiếp theo chúng ta chuyển sang cài đặt DB. Bạn có thể nhập dữ liệu và thậm chí cả DBMS của mình; Tôi nhắc lại, tôi sử dụng H2 DB để đơn giản.

    JPA Entities and DB Relationships - 3

    Tiếp theo, hãy thiết lập mạch. Bước này là tùy chọn nhưng được khuyến nghị nếu bạn có nhiều lược đồ trong cơ sở dữ liệu.

    JPA Entities and DB Relationships - 4

    Áp dụng các cài đặt và cuối cùng chúng ta sẽ nhận được kết quả như thế này:

    JPA Entities and DB Relationships - 5
  2. Chúng tôi đã tạo cơ sở dữ liệu và định cấu hình quyền truy cập vào cơ sở dữ liệu đó từ IDEA. Bây giờ bạn cần tạo các bảng trong đó và điền vào đó một số dữ liệu. Ví dụ: tôi sẽ lấy hai thực thể: Tác giả và Sách. Một cuốn sách có thể có một tác giả, có thể có nhiều tác giả hoặc không có một tác giả nào. Trong ví dụ này, chúng tôi sẽ tạo tất cả các loại kết nối. Nhưng tại thời điểm này - mối quan hệ Một-Một. Hãy tạo tập lệnh tương ứng để tạo Bảng 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)
    );

    Và hãy thực hiện nó:

    JPA Entities and DB Relationships - 6

    Kết quả thực thi trong bảng điều khiển:

    JPA Entities and DB Relationships - 7

    Kết quả trong DB:

    JPA Entities and DB Relationships - 8
  3. Hãy nhìn vào sơ đồ các bảng của chúng tôi. Để làm điều này, RMB trên DB của chúng tôi:

    JPA Entities and DB Relationships - 9

    Kết quả:

    JPA Entities and DB Relationships - 10

    Trên sơ đồ UML chúng ta có thể thấy tất cả các khóa chính và khóa ngoại, chúng ta cũng thấy được kết nối giữa các bảng của mình.

  4. Hãy viết một tập lệnh điền dữ liệu thử nghiệm vào DB của chúng tôi:

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

    Ý tôi là, chuyện gì xảy ra vậy? Mối quan hệ một-một là cần thiết khi thực thể của một bảng có liên quan đến thực thể của một bảng khác (hoặc hoàn toàn không liên quan nếu NOT NULL bị xóa khỏi BOOK_ID). Trong ví dụ của chúng tôi, một cuốn sách PHẢI có một tác giả. Không con cach nao khac.

  5. Bây giờ điều thú vị nhất là làm thế nào để kết nối một lớp Java với các thực thể DB? Rất đơn giản. Hãy tạo hai lớp Sách và Tác giả. Bằng một ví dụ, tôi sẽ phân tích lớp 1 và các trường giao tiếp chính. Hãy lấy lớp Author làm ví dụ :

    @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;
    }
Hãy tìm ra nó theo thứ tự:
  1. Tất cả các trường trong lớp đều lặp lại các thuộc tính của thực thể DB.
  2. @Data (từ Lombok ) nói rằng đối với mỗi trường, một getter và setter sẽ được tạo, bằng, mã băm sẽ bị ghi đè và phương thức toString sẽ được tạo.
  3. @Entity nói rằng lớp đã cho là một thực thể và được liên kết với một thực thể DB.
  4. @DynamicInsert@DynamicUpdate nói rằng việc chèn và cập nhật động sẽ được thực hiện trong DB. Đây là những cài đặt Hibernate sâu hơn sẽ hữu ích cho bạn để bạn có được việc phân nhóm ĐÚNG.
  5. @Table (name = "AUTHOR") liên kết lớp Sách với bảng DB AUTHOR.
  6. @Id nói rằng trường này là khóa chính.
  7. @GeneratedValue (strategy = GenerationType.IDENTITY) – chiến lược tạo khóa chính.
  8. @Column (name = "ID", nullable = false) liên kết một trường với thuộc tính DB và cũng cho biết rằng trường DB đã cho không thể rỗng. Điều này cũng hữu ích khi tạo bảng từ các thực thể. Quy trình ngược lại với cách chúng tôi tạo dự án hiện tại, điều này cần thiết trong DB thử nghiệm cho các bài kiểm tra Đơn vị.
  9. @OneToOne nói rằng trường đã cho là trường mối quan hệ Một-Một.
  10. @JoinColumn (name = "BOOK_ID", duy nhất = true, nullable = false) - một cột BOOK_ID sẽ được tạo, cột này là duy nhất và không rỗng.
Ở mặt ngược lại (trong lớp Sách ), chúng ta cũng cần tạo kết nối Một-Một và chỉ ra trường nơi ánh xạ xảy ra. @OneToOne(mappedBy = "book") - trong ví dụ này, đây là trường sách của lớp Tác giả. JPA sẽ tự liên kết chúng. Thoạt nhìn có vẻ như có rất nhiều chú thích nhưng thực tế nó rất tiện lợi và với kinh nghiệm, bạn sẽ tự động thêm chúng mà không cần suy nghĩ.
  1. Bây giờ hãy cấu hình Hibernate. Để thực hiện việc này, hãy tạo tệp 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>
Mô tả thuộc tính :
  1. hibernate.dialect là phương ngữ của DBMS mà chúng tôi đã chọn.
  2. hibernate.connection.driver_class - Lớp trình điều khiển của DB của chúng tôi.
  3. hibernate.connection.url - utl của DB của chúng tôi. Bạn có thể bắt đầu từ điểm đầu tiên khi chúng tôi định cấu hình DB.
  4. hibernate.connection.username - Tên người dùng DB.
  5. hibernate.connection.password - Mật khẩu người dùng DB.
  6. hibernate.hbm2ddl.auto - thiết lập việc tạo bảng. Nếu cập nhật thì nó sẽ không tạo ra nếu nó đã được tạo mà chỉ cập nhật nó.
  7. hibernate.show_sql - có hiển thị truy vấn DB hay không.
  8. hibernate.format_sql - có định dạng truy vấn DB hay không. Nếu không thì tất cả chúng sẽ nằm trên một dòng. Tôi khuyên bạn nên bật nó lên.
  9. hibernate.use_sql_comments - nhận xét truy vấn DB. Nếu đây là một Phụ trang thì một nhận xét sẽ được viết phía trên yêu cầu rằng yêu cầu đó thuộc loại Phụ trang.
  10. hibernate.generate_statistics - tạo nhật ký. Tôi khuyên bạn nên thiết lập đăng nhập ở mức tối đa. Đọc nhật ký sẽ tăng cơ hội làm việc chính xác với ORM.
  11. hibernate.jdbc.batch_size - Kích thước lô tối đa.
  12. hibernate.jdbc.fetch_size - Kích thước tìm nạp tối đa.
  13. hibernate.order_inserts - cho phép chèn động.
  14. hibernate.order_updates - Cho phép cập nhật động.
  15. hibernate.jdbc.batch_versioned_data - cho phép phân nhóm. Nhìn vào DBMS của bạn: không phải ai cũng hỗ trợ điều này.
  16. lớp ánh xạ - các lớp là thực thể của chúng tôi. Tất cả mọi thứ cần phải được liệt kê.
  1. Bây giờ bản chất của chúng ta phải được xác định. Chúng ta có thể kiểm tra điều này trong tab kiên trì:

    JPA Entities and DB Relationships - 11

    Kết quả:

    JPA Entities and DB Relationships - 12
  2. Chúng ta cũng cần định cấu hình dữ liệu gán:

    JPA Entities and DB Relationships - 13 JPA Entities and DB Relationships - 14

    Kết quả: Chúng tôi đã thực hiện lập bản đồ One-to-One. Tài liệu chỉ nhằm mục đích thông tin, chi tiết có trong tài liệu tham khảo.

Mối quan hệ một-nhiều

Liên kết đến chi nhánh ở đây . Mình sẽ không đăng code vào bài viết nữa vì đã quá dài rồi. Chúng tôi xem xét tất cả mã trên GitHub.
  1. Kết quả của việc thực thi tập lệnh khởi tạo, chúng tôi nhận được như sau:

    JPA Entities and DB Relationships - 15

    Bạn có cảm thấy sự khác biệt so với bảng trước không?

  2. Biểu đồ:

    JPA Entities and DB Relationships - 16

    Mối quan hệ một-nhiều - một tác giả có thể có nhiều cuốn sách. Thực thể bên trái tương ứng với một hoặc nhiều thực thể bên phải.

  3. Sự khác biệt trong ánh xạ sẽ nằm ở chú thích và trường:

    Một trường xuất hiện trong lớp Tác giả :

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

    Nó đã là một bộ rồi vì chúng ta có thể có nhiều cuốn sách. @OneToMany đang nói về loại mối quan hệ. FetchType.Lazy nói rằng chúng tôi không cần tải toàn bộ danh sách sách nếu nó không được chỉ định trong yêu cầu. Cũng cần phải nói rằng KHÔNG THỂ thêm trường này vào toString, nếu không chúng ta sẽ bắt đầu tạo ra StackOverflowError. Lombok yêu quý của tôi sẽ lo việc này:

    @ToString(exclude = "books")

    Trong lớp Sách , chúng tôi thực hiện phản hồi Nhiều-Một:

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

    Ở đây chúng tôi kết luận rằng Một-nhiều là hình ảnh phản chiếu của Nhiều-một và ngược lại. Cần nhấn mạnh rằng Hibernate không biết gì về truyền thông hai chiều. Đối với anh, đây là hai kết nối khác nhau: một hướng, một hướng ngược lại.

  4. Không có gì thay đổi nhiều trong hibernate.cfg.xml .

  5. Kiên trì:

    JPA Entities and DB Relationships - 17

Mối quan hệ nhiều-một

Vì Nhiều-một là hình ảnh phản chiếu của Một-nhiều nên sẽ có một vài điểm khác biệt. Liên kết đến chi nhánh ở đây .
  1. Kết quả thực thi tập lệnh khởi tạo, chúng ta nhận được kết quả như sau:

    JPA Entities and DB Relationships - 18
  2. Biểu đồ:

    JPA Entities and DB Relationships - 19
  3. Sự khác biệt trong ánh xạ sẽ nằm ở chú thích và trường:

    Không còn một tập hợp nào trong lớp Tác giả nữa vì nó đã được chuyển sang lớp Sách .

  4. ngủ đông.cfg.xml

  5. Kiên trì:

    JPA Entities and DB Relationships - 20

Mối quan hệ nhiều-nhiều

Hãy chuyển sang mối quan hệ thú vị nhất. Mối quan hệ này, theo tất cả các quy tắc đứng đắn và không đứng đắn, được tạo ra thông qua một bảng bổ sung. Nhưng bảng này không phải là một thực thể. Thật thú vị phải không? Chúng ta hãy nhìn vào cái chết tiệt này. Liên kết đến chi nhánh ở đây .
  1. Nhìn vào script khởi tạo , một bảng HAS bổ sung xuất hiện ở đây. Chúng tôi nhận được một cái gì đó giống như tác giả có sách.

    Kết quả thực thi tập lệnh, chúng ta sẽ nhận được các bảng sau:

    JPA Entities and DB Relationships - 21
  2. Biểu đồ:

    JPA Entities and DB Relationships - 22

    Trong ví dụ của chúng tôi, hóa ra một cuốn sách có thể có nhiều tác giả và một tác giả có thể có nhiều cuốn sách. Chúng có thể chồng lên nhau.

  3. Các lớp ánh xạ sẽ có các tập hợp trong các lớp. Nhưng như tôi đã nói, bảng HAS không phải là một thực thể.

    Lớp tác giả :

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

    @ManyToMany là một loại mối quan hệ.

    @JoinTable - đây chính xác là thứ sẽ kết nối thuộc tính với bảng HAS bổ sung. Trong đó chúng tôi chỉ định hai thuộc tính sẽ trỏ đến khóa chính của hai thực thể.

    Lớp sách :

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

    Ở đây chúng tôi chỉ ra FetchType và trường chúng tôi sẽ sử dụng để ánh xạ.

  4. Một lần nữa, hibernate.cfg.xml của chúng tôi vẫn không thay đổi (tôi không tính đến thực tế là chúng tôi đã tạo một DB mới cho mỗi nhánh).

  5. Kiên trì:

    JPA Entities and DB Relationships - 23

Phỏng vấn

Vì vậy, chúng tôi đã xem xét sơ bộ các loại mối quan hệ DB và tìm ra cách triển khai chúng trong mô hình ORM. Chúng tôi đã viết một dự án thử nghiệm thể hiện tất cả các kết nối và tìm ra cách định cấu hình chế độ ngủ đông/jpa. Phù.

Liên kết hữu ích

Các bài viết trước đây của tôi: PS Có thể có sai sót và thiếu sót trong văn bản. PPS Tác giả đã hút thứ gì đó lạ khi viết bài này. Cám ơn vì sự quan tâm của bạn!
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION