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

时间:2018-10-25 11:32:51

标签: sql hibernate race-condition optimistic-locking pessimistic-locking

在提交当前事务之前,休眠状态检查该行的版本时,它应发出一条SQL select语句以获取该行。

假定在发出select语句后,休眠状态发现行版本未更改,因此应继续提交事务。

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

如果我的想法是真的:

  • 然后,休眠乐观锁定实际上会对其进行操作使用悲观锁定,尽管该悲观锁定会保留很短的时间,因为事务将在此之后立即提交。

  • 否则,我们在行版本检查和提交之间会有很短的时间间隔,这可能会导致竞争状况。

请分享您的想法。

1 个答案:

答案 0 :(得分:1)

对于默认的乐观锁定机制(由@Version批注给出的机制),没有这种风险。

this article中所述,开放式锁定不需要任何额外的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仅检查updateCount方法调用的PreparedStatement.executeUpdate结果。如果计数不是updateCount,则意味着该行已删除或版本已更改,这意味着我们正在使用陈旧数据,因此将抛出OptimisticLockException

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

this article中所述,只有显式LockModeType.OPTIMISTIC会导致竞争状态。但是,您可以轻松fix that using a pessimistic shared or explicit lock