2014-07-17 15 views
6

tôi đang học JPA Tài liệu và gặp dòng sau:PessimisticLockScope.NORMAL và khóa "mối quan hệ"

mối quan hệ thực thể mà tổ chức khóa chứa nước ngoài chính cũng sẽ bị khóa, nhưng không phải là trạng thái của đối tượng được tham chiếu (trừ khi các thực thể đó bị khóa rõ ràng). Các bộ sưu tập phần tử và các mối quan hệ mà thực thể không chứa khóa ngoài (chẳng hạn như các mối quan hệ được ánh xạ để nối bàn hoặc các mối quan hệ một-nhiều chiều mà thực thể đích chứa khóa ngoại) sẽ không bị khóa theo mặc định.

nó từ here (PessimisticLockScope.NORMAL)

Tôi tự hỏi làm thế nào để giải thích những dòng này. Nếu PessimisticLockScope được đặt thành EXTENDED thì các hàng trong bảng tham gia cũng bị khóa (nhưng không phải là các thực thể liên quan), vì vậy khi sử dụng giá trị NORMAL, những gì sẽ bị khóa? Chắc chắn hàng thực thể (hoặc các hàng nếu chiến lược thừa kế là JOINED hoặc TABLE_PER_CLASS hoặc nếu có một SecondaryTable), nhưng những gì có nghĩa là "mối quan hệ thực thể":

mối quan hệ thực thể mà tổ chức khóa chứa nước ngoài chủ chốt cũng sẽ bị khóa

trong ngữ cảnh PessimisticLockScope.NORMAL?

Trả lời

4

Mối quan hệ thực thể được ánh xạ tới các liên kết FK cơ sở dữ liệu.

Các PessimisticLockScope.NORMAL sẽ phát hành một cơ sở dữ liệu khóa độc quyền khá tích cực trên:

  • thực thể tách ra bảng hàng
  • trong một cấu trúc thừa kế bảng tham gia cả hai bảng cơ sở và các bảng phân lớp sẽ được khóa
  • tất cả @ManyToOne@OneToOne các hàng trong bảng được liên kết có mối quan hệ FK thực tế (ví dụ: mặt có @JoinColumn). Nhưng điều đó có nghĩa là bạn không thể thay đổi thông tin FK, nghĩa là bạn không thể đặt thông tin đó thành giá trị null hoặc bất kỳ giá trị khác nào khác. Vì vậy, chỉ có giá trị cột FK bị khóa chứ không phải hàng FK được liên kết với bảng khác.

Các @OneToMany, @ManyToMany và không sở hữu @OneToOne@ManyToOne hiệp hội sẽ không bị khóa lại bởi vì những hiệp hội chỉ có một Object-Oriented tương đương và các khóa xảy ra chỉ ở cấp cơ sở dữ liệu. Để biết thêm chi tiết, hãy xem this article.

Các PessimisticLockScope.EXTENDED cũng sẽ mở rộng đến các liên kết @OneToMany@ManyToMany. Nhưng một lần nữa, điều này chỉ áp dụng cho các giá trị cột FK không cho toàn bộ các hàng. Vì vậy, khóa này sẽ ngăn chặn việc thêm/xóa các phần tử vào/từ các liên kết @OneToMany/@ManyToMany. Nó không ngăn không cho các thành phần chứa được cập nhật. Đối với điều đó, bạn sẽ phải khóa mỗi thực thể chứa.

+0

Cảm ơn bạn! Nó rõ ràng hơn nhiều so với trong Tài liệu JPA. –

+0

Giải thích tuyệt vời @Vlad. Bạn có thể giải thích thêm một chút về "điều này chỉ áp dụng cho các giá trị cột FK không cho toàn bộ hàng". Bạn có nghĩa là chỉ có một cột bị khóa thay vì hàng. Khóa này được dịch sang cơ sở dữ liệu như thế nào. AFAIK, độ chi tiết của khóa là hàng và không phải cột HOẶC khóa liên quan này chỉ ở trong bộ nhớ. – Shailendra

+1

Tôi đã đề cập đến hàng chứa FK (và thực sự là khóa được lấy cho toàn bộ hàng, không chỉ là một cột đơn lẻ) không phải là hàng được tham chiếu bởi cột FK. –

2

Dưới đây là một vài thử nghiệm liên quan đến câu hỏi. Tôi đang sử dụng Hibernate 4.3.6 là nhà cung cấp JPA và MySQL 5.6 làm cơ sở dữ liệu.

Rất ít các đơn vị kiểm tra - TestPerson, TestUser, TestOrder

TestUser kéo dài TestPerson (với thừa kế tham gia) và TestUser có một danh sách OneToMany hai chiều của TestOrders mã tạo

@Entity 
@Inheritance(strategy = InheritanceType.JOINED) 
public class TestPerson { 

    @Id 
    @GeneratedValue(strategy=GenerationType.AUTO) 
    private long id; 

    private String name; 
    private String address; 

    //getters and setters 



@Entity 
public class TestUser extends TestPerson { 

    @OneToMany(fetch=FetchType.LAZY,mappedBy="user") 
    private List<TestOrder> orders ; 

    //getters and setters 


@Entity 
public class TestOrder { 

    @Id 
    @GeneratedValue(strategy=GenerationType.AUTO) 
    private long id; 

    @ManyToOne 
    @JoinTable(name="test_user_orders") 
    private TestUser user; 

    private String orderNumber ; 

    //getters and setters** 

dữ liệu:

  em.getTransaction().begin();    
     TestUser user = new TestUser(); 
     user.setName("TestUser"+System.currentTimeMillis()); 
     user.setAddress("TestUserAddress1"); 
     em.persist(user); 
     List<TestOrder> orders = new ArrayList(); 
     for (int i=1;i<6;i++){ 
     TestOrder order = new TestOrder(); 
     order.setOrderNumber("ON"+System.currentTimeMillis()); 
     order.setUser(user); 
     em.persist(order); 
     orders.add(order); 
     } 
     user.setOrders(orders); 

     em.getTransaction().commit(); 
     em.close(); 




mysql> select * from test_person; 
+----+------------------+-----------------------+ 
| id | address   | name     | 
+----+------------------+-----------------------+ 
| 1 | TestUserAddress1 | TestUser1406031063539 | 
+----+------------------+-----------------------+ 
1 row in set (0.00 sec) 


mysql> select * from test_user; 
+----+ 
| id | 
+----+ 
| 1 | 
+----+ 


mysql> select * from test_order; 
+----+-----------------+ 
| id | order_number | 
+----+-----------------+ 
| 1 | ON1406031063627 | 
| 2 | ON1406031063673 | 
| 3 | ON1406031063678 | 
| 4 | ON1406031063683 | 
| 5 | ON1406031063686 | 
+----+-----------------+ 



mysql> select * from test_user_orders; 
+------+----+ 
| user | id | 
+------+----+ 
| 1 | 1 | 
| 1 | 2 | 
| 1 | 3 | 
| 1 | 4 | 
| 1 | 5 | 
+------+----+ 

Bây giờ, hãy tra cứu MnayToOne bên nghĩa là, TestOrder

Map<String, Object> map = new HashMap<String, Object>(); 
map.put("javax.persistence.lock.scope", PessimisticLockScope.EXTENDED); 
TestOrder order = em2.find(TestOrder.class, new Long(1), LockModeType.PESSIMISTIC_WRITE, map); 

Lưu ý "để cập nhật" trong truy vấn để khóa bi quan. Truy vấn này cũng có bảng tham gia.

select 
     testorder0_.id as id1_8_0_, 
     testorder0_.order_number as order_nu2_8_0_, 
     testorder0_1_.user as user1_11_0_ 
    from 
     test_order testorder0_ 
    left outer join 
     test_user_orders testorder0_1_ 
      on testorder0_.id=testorder0_1_.id 
    where 
     testorder0_.id=? for update 

Hibernate: 
    select 
     testuser0_.id as id1_9_0_, 
     testuser0_1_.address as address2_9_0_, 
     testuser0_1_.name as name3_9_0_ 
    from 
     test_user testuser0_ 
    inner join 
     test_person testuser0_1_ 
      on testuser0_.id=testuser0_1_.id 
    where 
     testuser0_.id=? 

Ngoài ra khi tôi truy vấn cho người dùng, lần này chỉ các bảng tham gia vào sử dụng hệ thống phân cấp được khóa bằng cách "để cập nhật"

Map<String, Object> map = new HashMap<String, Object>(); 
     map.put("javax.persistence.lock.scope", PessimisticLockScope.EXTENDED); 
     TestUser user = em2.find(TestUser.class, new Long(2), LockModeType.PESSIMISTIC_WRITE,map); 
     user.getOrders().size(); // to force initialization of orders 

SQL kết quả là:

 select 
     testuser0_.id as id1_9_0_, 
     testuser0_1_.address as address2_9_0_, 
     testuser0_1_.name as name3_9_0_ 
    from 
     test_user testuser0_ 
    inner join 
     test_person testuser0_1_ 
      on testuser0_.id=testuser0_1_.id 
    where 
     testuser0_.id=? for update 

Hibernate: 
    select 
     orders0_.user as user1_9_0_, 
     orders0_.id as id2_11_0_, 
     testorder1_.id as id1_8_1_, 
     testorder1_.order_number as order_nu2_8_1_, 
     testorder1_1_.user as user1_11_1_ 
    from 
     test_user_orders orders0_ 
    inner join 
     test_order testorder1_ 
      on orders0_.id=testorder1_.id 
    left outer join 
     test_user_orders testorder1_1_ 
      on testorder1_.id=testorder1_1_.id 
    where 
     orders0_.user=? 
+0

Đó là giải thích thực sự tốt về những gì 'EXTENDED' làm, nhưng câu hỏi của tôi là về' PessimisticLockScope.NORMAL' và 'Các mối quan hệ thực thể mà thực thể bị khóa chứa khóa ngoài cũng sẽ bị khóa' từ tài liệu (được đặt dưới giá trị 'NORMAL'). –

Các vấn đề liên quan