Hibernate如何在提交事务之前对乐观锁定进行行版本检查



当hibernate在提交当前事务之前检查行的版本时,它应该发出一条sqlselect语句来获取该行。

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

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

如果我的想法是真的:

  • 则hibernate乐观锁定实际上使用悲观锁定进行操作,尽管该悲观锁定保持的时间很短,因为之后将立即提交事务。

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

请分享您的想法。

对于默认的乐观锁定机制,即@Version注释给出的机制,不存在这样的风险。

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

  1. 从数据库中提取实体及其版本:

    SELECT * FROM PRODUCT WHERE ID = 1;
    
  2. UPDATE或DELETE将使用由获取实体的SELECT获取的版本:

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

因此,Hibernate不会检查实体版本。DB使用WHERE子句进行检查。

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

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

只有明确的LockModeType.OPTIMISTIC才能导致竞争条件。但是,使用悲观共享锁或显式锁可以很容易地解决这个问题。

最新更新