[英]Concurrency with Hibernate in Spring
我发现了很多关于这个主题的帖子,但所有答案都只是没有示例代码的文档链接,即如何在实践中使用并发。
我的情况:我有一个实体House
(用于简化)两个属性, number
(id)和owner
。 数据库初始化为10个Houses
, number
1-10, owner
始终为null
。
我想为房子分配一个新的所有者,目前没有所有者,而且number
最少。 我的代码看起来像这样:
@Transactional
void assignNewOwner(String newOwner) {
//this is flagged as @Transactional too
House tmp = houseDao.getHouseWithoutOwnerAndSmallestNumber();
tmp.setOwner(newOwner);
//this is flagged as @Transactional too
houseDao.update(tmp);
}
根据我的理解,虽然使用了@Transactional
,但如果两个请求获取与tmp
相同的空House
,则可以将同一个House
分配给不同的所有者两次。 我如何确保不会发生这种情况?
我知道,包括选择空House
的更新会解决问题,但在不久的将来,我想更多地修改/使用tmp
对象。
乐观
如果向实体/表添加版本列,则可以利用称为乐观锁定的机制。 这是确保实体状态自从我们在事务上下文中获取后未发生变化的最熟练方法。
使用session
createQuery
,您可以调用setLockMode(LockModeType.OPTIMISTIC);
然后,就在提交事务之前,持久性提供程序将查询该实体的当前版本并检查它是否已被另一个事务递增。 如果是这样,您将获得OptimisticLockException和事务回滚。
悲观
如果您没有对行进行版本控制,那么您将留下悲观的lockin,这基本上意味着您在数据库级别上为查询实体创建了一个锁,而其他事务无法读取/更新这些特定的行。
您可以通过在Query
对象上设置它来实现:
setLockMode(LockModeType.PESSIMISTIC_READ);
要么
setLockMode(LockModeType.PESSIMISTIC_WRITE);
实际上这很容易 - 至少在我看来,当你说Pessimistic/Optimistic
时,我将抽象出Hibernate
会产生什么。 您可能认为这是SELECT FOR UPDATE
- 但情况并非总是如此,MSSQL AFAIK没有...
这些是JPA
注释,它们保证了一些功能,而不是实现。
从根本上说,它们完全不同 - PESSIMISTIC
与OPTIMISTIC
锁定。 当您进行悲观锁定时,您至少在逻辑上执行synchronized block
- 您可以执行任何操作,并且在事务范围内是安全的。 现在,无论是为row, table or even page
保持锁定都是未指定的; 所以有点危险。 通常数据库可能会升级锁,如果我正确地重新调用,MSSQL会这样做。
锁定饥饿显然是一个问题,因此您可能认为OPTIMISTIC
锁定会有所帮助。 作为旁注,这是transactional memory is in modern CPU
; 他们使用相同的思维过程。
所以乐观锁定就像说 - 我将用ID / Date等标记这一行,然后我会拍摄它的快照并使用它 - 在提交之前我将检查该Id是否有更改。 显然,该ID
存在争议,但数据存在争议。 如果它已经改变 - 中止(也就是抛出OptimisticLockException
)否则提交工作。
困扰每个人IMO的事情是OptimisticLockException
- 你如何从中恢复? 这是你不会喜欢的东西 - 这取决于你 。 有些应用程序可以进行简单的重试,有些应用程序可能无法实现。 我在极少数情况下使用它。
我通常采用Pessimistic
锁定(除非Optimistic
完全不是一种选择)。 同时我会看看hibernate为该查询生成了什么。 例如,您可能需要一个index
来检索如何检索DB
以实际锁定该行 - 因为最终这就是您想要的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.