JPA PessimisticLockScope.NORMAL并锁定“关系”
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JPA PessimisticLockScope.NORMAL并锁定“关系”相关的知识,希望对你有一定的参考价值。
我正在研究JPA文档,遇到以下几行:
锁定实体包含外键的实体关系也将被锁定,但不会锁定所引用实体的状态(除非明确锁定这些实体)。实体不包含外键的元素集合和关系(例如映射到连接表的关系或目标实体包含外键的单向一对多关系)默认情况下不会被锁定。
它来自here(PessimisticLockScope.NORMAL
)
我想知道如何解释这些线条。如果PessimisticLockScope
设置为EXTENDED
,那么连接表中的行也会被锁定(但不是相关的实体本身),所以当使用NORMAL
值时会锁定什么?对于确定的实体行(如果继承策略是JOINED
或TABLE_PER_CLASS
,或者如果有SecondaryTable
,则为行),但是“实体关系”是什么意思:
锁定的实体包含外键的实体关系也将被锁定
在PessimisticLockScope.NORMAL
的背景下?
实体关系映射到数据库FK关联。
PessimisticLockScope.NORMAL
将发布一个非常积极的数据库独占锁定:
- 实体分离表行
- 在连接表继承结构中,基表和子类表都将被锁定
- 所有
@ManyToOne
和@OneToOne
关联的表行具有实际的FK关系(例如,与@JoinColumn
的一侧)。但这意味着您无法更改FK信息,这意味着您无法将其设置为null或任何其他不同的值。因此,只有FK列值被锁定而不是其他表关联的FK行。
@OneToMany
,@ManyToMany
和非拥有的@OneToOne
和@ManyToOne
关联不会被锁定,因为这些关联只有一个面向对象的等价物,并且锁定只发生在数据库级别。有关更多详细信息,请查看this article。
PessimisticLockScope.EXTENDED
也将扩展到@OneToMany
和@ManyToMany
协会。但同样,这仅适用于FK列值而不适用于整行。因此,此锁定将阻止向/从@OneToMany
/ @ManyToMany
关联添加/删除元素。它不会阻止包含的元素更新。为此,您必须锁定每个包含的实体。
以下是关于这个问题的一些实验。我使用Hibernate 4.3.6作为JPA提供程序,使用mysql 5.6作为数据库。
很少有测试实体 - TestPerson,TestUser,TestOrder
TestUser扩展了TestPerson(带有JOINED继承),TestUser有一个双向的OneToMany TestOrders列表
@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**
数据创建代码:
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 |
+------+----+
现在查找MnayToOne端,即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);
请注意悲观锁定查询中的“for update”。此查询也包含连接表。
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=?
此外,当我查询用户时,这次只有用户层次结构中涉及的表被“for update”锁定
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是:
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=?
以上是关于JPA PessimisticLockScope.NORMAL并锁定“关系”的主要内容,如果未能解决你的问题,请参考以下文章