你之前这么说:
锁的目的是防止多个事务
从数据库读取数据,因为该数据影响生成
新数据并在交易方面发生变化。
甲骨文使用MVCC (Multiversion Concurrency Control) https://vladmihalcea.com/how-does-mvcc-multi-version-concurrency-control-work/所以读者不会阻止作家,作家也不会阻止读者。即使您使用 Oracle 获取了行级锁,并且在未提交的情况下修改了该行,其他事务仍然可以读取最后提交的值。
与此日志消息相关:
org.hibernate.loader.Loader - HHH000444: Encountered request for locking however dialect reports that database prefers locking be done in a separate select (follow-on locking); results will be locked after initial query executes
后续锁定机制是由于Oracle在进行Oracle 11g分页时无法应用锁,使用DISTINCT
or UNION ALL
.
如果您使用的是 Oracle 12i,则可以将 Hibernate 方言更新为Oracle12cDialect
由于 Oracle 12 使用 SQL 标准分页并且不再需要派生表查询,因此分页和锁定将正常工作。
这在 MariaDB 或任何其他数据库中都不会发生。这只是 Oracle 12 之前的限制。
如果您使用 Hibernate 5.2.1,我们添加了一个新提示HINT_FOLLOW_ON_LOCKING http://docs.jboss.org/hibernate/orm/5.2/javadocs/org/hibernate/jpa/QueryHints.html#HINT_FOLLOW_ON_LOCKING这会禁用此机制。
因此,您的 Spring Data 查询将变为:
@QueryHints(value = { @QueryHint(name = "hibernate.query.followOnLocking", value = "false")}, forCounting = false)
@Lock(LockModeType.PESSIMISTIC_WRITE)
User findUserById(@Param("id") String operatorId);
您也可以手动应用它:
User user = entityManager.createQuery(
"select u from User u where id = :id", User.class)
.setParameter("id", id);
.unwrap( Query.class )
.setLockOptions(
new LockOptions( LockMode.PESSIMISTIC_WRITE )
.setFollowOnLocking( false ) )
.getSingleResult();