gpt4 book ai didi

java - 如何使 Hibernate @Lock 注释适用于 Oracle DB?

转载 作者:搜寻专家 更新时间:2023-11-01 01:25:06 24 4
gpt4 key购买 nike

我偶然发现了 Oracle 数据库中锁定行的问题。锁的目的是防止多个事务从数据库中读取数据,因为这些数据会影响新数据的生成,并且会根据事务进行更改。

为了锁定,我在 SpringData 查找方法上放置了 @Lock 注释,该方法检索参与事务的数据。

@Lock(LockModeType.PESSIMISTIC_WRITE)
User findUserById(@Param("id") String operatorId);

执行此代码后,我收到日志消息

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

除此之外,无果无因

org.springframework.dao.DataIntegrityViolationException: could not execute batch; SQL [insert into ...]

使用entity manager重写锁可以解决

entityManager.lock(userByIdWithLockOnReadWrite, LockModeType.PESSIMISTIC_WRITE);    

entityManager.unwrap(Session.class).lock(userByIdWithLockOnReadWrite, LockMode.PESSIMISTIC_WRITE);

该问题未出现在 MariaDB (MySQL) 上。

也许使用注释有一些特殊的规则?

最佳答案

你说的是:

The purpose of the lock is to prevent more than one transactionreading data from the DB because this data influences the generationof new data and is changed in terms of a transaction.

Oracle 使用 MVCC (Multiversion Concurrency Control)所以读者不会阻止作家,作家也不会阻止读者。即使您获得了 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分页时无法应用锁,使用DISTINCTUNION ALL

如果您使用的是 Oracle 12i,那么您可以将 Hibernate 方言更新为 Oracle12cDialect,分页和锁定将正常工作,因为 Oracle 12 使用 SQL 标准分页并且不再需要派生表查询。

这不会发生在 MariaDB 或任何其他数据库中。这只是 Oracle 12 之前的限制。

如果您使用的是 Hibernate 5.2.1,我们添加了一个新提示 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();

关于java - 如何使 Hibernate @Lock 注释适用于 Oracle DB?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40115158/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com