Hibernate 如何在提交事务之前对 Optimistic Locking 进行行版本检查

Posted

技术标签:

【中文标题】Hibernate 如何在提交事务之前对 Optimistic Locking 进行行版本检查【英文标题】:How does Hibernate do row version check for Optimistic Locking before committing the transaction 【发布时间】:2019-03-30 00:11:37 【问题描述】:

当在提交当前事务之前休眠检查行的版本,它应该发出一个 sql select 语句来获取它。

假设在发出select 语句后休眠发现行版本没有改变,因此它应该继续提交事务。

我想知道 hibernate 如何确保在选择行和提交当前事务之间的时间段内没有任何其他事务会更新该行以更改其版本号? hibernate 唯一可能做的事情似乎是使用Select ... For Update 进行悲观锁定的行版本选择或具有这样一个隔离级别的事务,它将锁定正在读取的行。

如果我的想法是真的:

那么休眠乐观锁确实使用悲观锁来进行操作,尽管该悲观锁的持有时间很短,因为此后事务将立即提交。

否则,我们在行版本检查和提交之间的时间间隔很短,可能会出现竞争条件。

请分享你的想法。

【问题讨论】:

【参考方案1】:

对于默认的乐观锁机制,@Version 注解给出的机制,没有这种风险。

乐观锁定不需要任何额外的 SELECT 来获取和检查实体修改后的版本。因此,涉及两个步骤:

    从数据库中获取实体及其版本:

     SELECT * FROM PRODUCT WHERE ID = 1;
    

    UPDATE 或 DELETE 将使用获取实体的同一 SELECT 获取的版本:

     UPDATE PRODUCT SET (LIKES, QUANTITY, VERSION) = (5, 10, 3) 
     WHERE ID = 1 AND VERSION = 2;
    

因此,Hibernate 不会检查实体版本。数据库使用 WHERE 子句对其进行检查。

Hibernate 只检查PreparedStatement.executeUpdate 方法调用的updateCount 结果。如果计数不是updateCount,则表示该行已被删除或版本已更改,这意味着我们使用的是陈旧数据,因此将抛出OptimisticLockException

因此,默认的基于@Version 的乐观锁定不会发生冲突,因为一条记录一次只能被一个事务修改,并且一旦该行被修改锁定,锁定将一直保留到事务提交或回滚。

只有显式的LockModeType.OPTIMISTIC 才能导致竞争条件。不过,您可以轻松fix that using a pessimistic shared or explicit lock。

【讨论】:

以上是关于Hibernate 如何在提交事务之前对 Optimistic Locking 进行行版本检查的主要内容,如果未能解决你的问题,请参考以下文章

spring怎么进行的事务管理,求指导?

Hibernate框架学习——事务

hibernate事务提交

spring与hibernate整合事务管理的理解

Infinispan/hibernate 2 级缓存更新不是事务性的?

方法完成后立即提交事务