Sự khác biệt giữa hiệp hội JPA đơn hướng và hai chiều và Hibernate là gì?


135

Sự khác biệt giữa các hiệp hội đơn hướng và hai chiều là gì?

Vì bảng được tạo trong db đều giống nhau, do đó, điểm khác biệt duy nhất tôi tìm thấy là mỗi bên của các giả định hai chiều sẽ có một tham chiếu đến bên kia, còn một hướng thì không.

Đây là một hiệp hội đơn hướng

public class User {
    private int     id;
    private String  name;
    @ManyToOne
    @JoinColumn(
            name = "groupId")
    private Group   group;
}

public class Group {
    private int     id;
    private String  name;
}

Hiệp hội hai chiều

public class User {
    private int     id;
    private String  name;
    @ManyToOne
    @JoinColumn(
            name = "groupId")
    private Group   group;
}
public class Group {
    private int         id;
    private String      name;
    @OneToMany(mappedBy="group")
    private List<User>  users;
}

Sự khác biệt là liệu nhóm giữ một tài liệu tham khảo của người dùng.

Vì vậy, tôi tự hỏi nếu đây là sự khác biệt duy nhất? được khuyến khích?


7
Bây giờ nhóm sẽ biết người dùng nào chứa nó. Tôi không nghĩ rằng đây là một sự khác biệt nhỏ.
Satadru Biswas

5
Mối quan hệ hai chiều trở thành một sự hỗn loạn đối với tôi khi cập nhật. :)
diyoda_

Câu trả lời:


152

Điểm khác biệt chính là mối quan hệ hai chiều cung cấp quyền truy cập điều hướng theo cả hai hướng, để bạn có thể truy cập vào phía bên kia mà không cần truy vấn rõ ràng. Ngoài ra, nó cho phép bạn áp dụng các tùy chọn xếp tầng cho cả hai hướng.

Lưu ý rằng truy cập điều hướng không phải lúc nào cũng tốt, đặc biệt là đối với các mối quan hệ "một-rất-nhiều" và "nhiều-rất-nhiều". Hãy tưởng tượng một Groupcái chứa hàng ngàn Users:

  • Làm thế nào bạn sẽ truy cập chúng? Với rất nhiều Users, bạn thường cần áp dụng một số bộ lọc và / hoặc phân trang, do đó bạn cần phải thực hiện một truy vấn nào đó (trừ khi bạn sử dụng bộ lọc bộ sưu tập , trông giống như một bản hack đối với tôi). Một số nhà phát triển có thể có xu hướng áp dụng lọc trong bộ nhớ trong những trường hợp như vậy, điều này rõ ràng không tốt cho hiệu suất. Lưu ý rằng có một mối quan hệ như vậy có thể khuyến khích loại nhà phát triển này sử dụng nó mà không xem xét ý nghĩa hiệu suất.

  • Làm thế nào bạn sẽ thêm Users mới vào Group? May mắn thay, Hibernate nhìn vào khía cạnh sở hữu của mối quan hệ khi duy trì nó, vì vậy bạn chỉ có thể thiết lập User.group. Tuy nhiên, nếu bạn muốn giữ các đối tượng trong bộ nhớ nhất quán, bạn cũng cần thêm Uservào Group.users. Nhưng nó sẽ khiến Hibernate tìm nạp tất cả các yếu tố Group.userstừ cơ sở dữ liệu!

Vì vậy, tôi không thể đồng ý với khuyến nghị từ Thực tiễn Tốt nhất . Bạn cần thiết kế các mối quan hệ hai chiều một cách cẩn thận, xem xét các trường hợp sử dụng (bạn có cần truy cập điều hướng theo cả hai hướng không?) Và các tác động hiệu quả có thể có.

Xem thêm:


Xin chào, cảm ơn, có vẻ như bạn là một chuyên gia về ngủ đông, vì bạn đã trả lời câu hỏi của tôi: stackoverflow.com/questions/5350770/ trên . Và bây giờ tôi không chắc chắn về mối quan hệ đang nắm giữ, vì tôi không thể viết thêm trong bình luận, vì vậy tôi đăng nó ở đây dpaste.de/J85m. Vui lòng kiểm tra nếu có thể. :)
hguser

@hguser: Nếu cuối cùng bạn quyết định làm cho bạn có mối quan hệ hai chiều, tôi nghĩ sẽ tốt hơn nếu gọi setGroup()từ addUser()đó để giữ cho cả hai bên nhất quán.
axtavt

Nếu tôi không gọi setgroup () trong nhóm.addUser () thì sao?
hguser

@hguser: Mối quan hệ sẽ không được duy trì, xem điểm 2 trong câu trả lời. Bạn có thể gọi setGroup()mà không có addUser(), nhưng nó sẽ dẫn đến trạng thái không nhất quán của các đối tượng trong bộ nhớ.
axtavt

Tôi thấy rằng tôi không thể lập bản đồ chính xác, bạn có thể dành chút thời gian để kiểm tra dự án của tôi tại github không? đó là một dự án nhỏ
hguser

31

Có hai sự khác biệt chính.

Tiếp cận các bên liên kết

Điều đầu tiên liên quan đến cách bạn sẽ truy cập vào mối quan hệ. Đối với một hiệp hội đơn hướng, bạn chỉ có thể điều hướng liên kết từ một đầu.

Vì vậy, đối với một @ManyToOnehiệp hội đơn hướng , điều đó có nghĩa là bạn chỉ có thể truy cập mối quan hệ từ phía trẻ em nơi khóa ngoại trú.

Nếu bạn có một @OneToManyhiệp hội đơn hướng , điều đó có nghĩa là bạn chỉ có thể truy cập mối quan hệ từ phía cha mẹ nơi khóa ngoại trú.

Đối với @OneToManyliên kết hai chiều , bạn có thể điều hướng liên kết theo cả hai cách, từ cha mẹ hoặc từ phía con.

Bạn cũng cần sử dụng các phương thức tiện ích thêm / xóa cho các hiệp hội hai chiều để đảm bảo rằng cả hai bên được đồng bộ hóa đúng cách .

Hiệu suất

Khía cạnh thứ hai liên quan đến hiệu suất.

  1. Đối với @OneToMany, các hiệp hội đơn hướng không thực hiện cũng như các hiệp hội hai chiều .
  2. Đối với @OneToOne, một liên kết hai chiều sẽ khiến phụ huynh được tìm nạp một cách háo hức nếu Hibernate không thể biết liệu Proxy có nên được gán hay giá trị null hay không .
  3. Đối với @ManyToMany, loại bộ sưu tập làm cho khá khác biệt là Setshoạt động tốt hơnLists .

11

Về mặt mã hóa, mối quan hệ hai chiều phức tạp hơn để thực hiện vì ứng dụng chịu trách nhiệm giữ cho cả hai bên đồng bộ theo đặc tả 5 của JPA (trên trang 42). Thật không may, ví dụ được đưa ra trong đặc tả không cung cấp thêm chi tiết, vì vậy nó không đưa ra ý tưởng về mức độ phức tạp.

Khi không sử dụng bộ đệm cấp hai, thường không có vấn đề gì khi không thực hiện đúng các phương thức quan hệ vì các trường hợp bị loại bỏ khi kết thúc giao dịch.

Khi sử dụng bộ đệm cấp hai, nếu bất cứ điều gì bị hỏng do phương thức xử lý mối quan hệ được thực hiện sai, điều này có nghĩa là các giao dịch khác cũng sẽ thấy các yếu tố bị hỏng (bộ đệm cấp hai là toàn cầu).

Một mối quan hệ hai chiều được triển khai chính xác có thể làm cho các truy vấn và mã đơn giản hơn, nhưng không nên được sử dụng nếu nó không thực sự có ý nghĩa về mặt logic kinh doanh.


9

Tôi không chắc chắn 100% đây là sự khác biệt duy nhất , nhưng nó là sự khác biệt chính . Các tài liệu Hibernate cũng được khuyến nghị nên có các hiệp hội hai chiều:

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/best-practices.html

Đặc biệt:

Thích các hiệp hội hai chiều: Các hiệp hội đơn hướng khó truy vấn hơn. Trong một ứng dụng lớn, hầu hết tất cả các hiệp hội phải có thể điều hướng theo cả hai hướng trong các truy vấn.

Cá nhân tôi có một vấn đề nhỏ với khuyến nghị chăn này - dường như có những trường hợp một đứa trẻ không có bất kỳ lý do thực tế nào để biết về cha mẹ của nó (ví dụ, tại sao một mục đặt hàng cần phải biết về đơn đặt hàng liên kết với?), nhưng tôi cũng thấy giá trị của nó là một phần hợp lý của thời gian. Và vì tính đa hướng không thực sự làm tổn thương bất cứ điều gì, tôi không thấy nó quá phản cảm để tuân thủ.


Các hướng hai chiều có thể bị tổn thương trong một số trường hợp, như axtavt đã giải thích! Tôi sẽ rất cẩn thận với mọi mối quan hệ được ánh xạ trong một thực thể Hibernate! Bạn có thể kết thúc với thời gian vô tận cần thiết để tải mọi thứ trong Hibernate, trừ khi bạn biết chính xác những gì bạn đang làm. Suy nghĩ cẩn thận về các trường hợp sử dụng và sử dụng các lớp mô hình khác nhau cho các trường hợp sử dụng khác nhau. F.ex trong một danh sách các thứ, tôi không cần tất cả các đối tượng liên quan, chỉ cần một nhãn và ID. Vì vậy, thực thể danh sách là một thực thể khác (và rất đơn giản) so với thực thể chi tiết, đối với tôi.
cslotty
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.