在提交当前事务之前,休眠状态检查该行的版本时,它应发出一条SQL select
语句以获取该行。
假定在发出select
语句后,休眠状态发现行版本未更改,因此应继续提交事务。
我想知道休眠状态如何确保在选择行和提交当前事务之间的时隙中,没有任何其他事务会更新更改其版本号的行吗?休眠唯一可能发生的事情似乎是使用Select ... For Update
进行悲观锁定的行版本选择,或者是具有这样隔离级别的事务,它将隔离正在读取的行。
如果我的想法是真的:
然后,休眠乐观锁定实际上会对其进行操作使用悲观锁定,尽管该悲观锁定会保留很短的时间,因为事务将在此之后立即提交。
否则,我们在行版本检查和提交之间会有很短的时间间隔,这可能会导致竞争状况。
请分享您的想法。
答案 0 :(得分:1)
对于默认的乐观锁定机制(由@Version
批注给出的机制),没有这种风险。
如this article中所述,开放式锁定不需要任何额外的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不会检查实体版本。 DB使用WHERE子句检查它。 Hibernate仅检查updateCount
方法调用的PreparedStatement.executeUpdate
结果。如果计数不是updateCount
,则意味着该行已删除或版本已更改,这意味着我们正在使用陈旧数据,因此将抛出OptimisticLockException
。
因此,对于默认的基于@Version
的乐观锁定,不会发生冲突,因为一次只能通过单个事务修改一条记录,并且一旦该行被修改锁定,该锁定即为保留,直到事务提交或回滚为止。
如this article中所述,只有显式LockModeType.OPTIMISTIC
会导致竞争状态。但是,您可以轻松fix that using a pessimistic shared or explicit lock。