选择从 JPA 级别锁定的更新跳过

Posted

技术标签:

【中文标题】选择从 JPA 级别锁定的更新跳过【英文标题】:Select for update skip locked from JPA level 【发布时间】:2017-05-16 23:51:10 【问题描述】:

在我的应用程序 - Oracle with JPA (EclipseLink) 中,我使用以下表达式来锁定某些表中的记录子集:

select * from MY_TABLE where MY_CONDITIONS for update skip locked

我在本机查询中运行它,但我必须为所有必需的实体编写该查询。

有没有办法使用纯 JPA 跳过锁定的记录?我可以实施自己的锁定策略吗?

我不介意更改 JPA 提供程序,但我想使用 JPA API。

【问题讨论】:

也许这有帮助 - blogs.oracle.com/enterprisetechtips/entry/… ?这真的不是 JPA 的用途。锁定整个表是可伸缩性杀手。也许重新考虑一下你想用这个来完成什么。 我同意,我没有锁定整个表,这个选择就是一个例子。我使用这种方法来避免锁定整个表。我锁定了接下来要更新的数据子集。我想忽略已经锁定的记录,因为如果其他进程拾取它,它们就不再与更新相关。 我看不到使用纯 JPA 执行此操作的方法,除非使用本机查询,因为跳过锁定是 Oracle 特定的并且不受 JPA 支持。您可能可以使用自定义方言完成它(例如Hibernate,EclipseLink 应该有类似的功能),但您仍然需要传达您希望特定查询使用该功能。 Hibernate 提供了 LockMode.UPGRADE_SKIPLOCKED 来完成这项工作,但 JPA 不支持。也许你可以通过混合 Hibernate 和 JPA 来完成这项工作,但听起来很乱! 【参考方案1】:

Hibernate 提供了 UPGRADE_SKIPLOCKED 锁定模式。

使用 JPA 和 Hibernate,要根据 Hibernate LockMode 文档生成“SKIP_LOCKED”,您必须结合 PESSIMISTIC_WRITE JPA LockModeType:

entityManager.find(Department.class, 1, LockModeType.PESSIMISTIC_WRITE);

还有锁定超时设置,例如在持久性单元的 persistence.xml 中:

<properties>
   <property name="javax.persistence.query.timeout" value="-2"/>
</properties>

(请注意,您也可以为复杂查询配置此 LockMode)

SKIP LOCKED 不是 ANSI SQL 的一部分。以下一些 RDBMS 将其作为特定功能提供:

mysql Postgresql Oracle

因此,对于纯 JPA,不可能在查询中指定“SKIP LOCKED”。 事实上,正如LockModeType 中所述,JPA 2.1 仅支持以下内容:

无 乐观 OPTIMISTIC_FORCE_INCREMENT PESSIMISTIC_FORCE_INCREMENT PESSIMISTIC_READ PESSIMISTIC_WRITE 阅读 写

但是,要在查询中启用 SKIP LOCKED,您可以使用以下替代方法:

使用特定的 JPA 实现功能,例如 Hibernate LockMode,它允许通过 JPA 查询指定 SKIP LOCKED,这要归功于如上所述的 PESSIMISTIC_WRITE LockModeType Lock Timeout 特定设置的组合 像您一样创建本机 SQL 查询

【讨论】:

是的,“选择 mailqueue0_.id as col_0_0_ from mailqueue mailqueue0_ where mailqueue0_.date @MaksimGumerov,您的 javax.persistence.lock.timeout 设置不正确。如答案中所述,您必须设置“-2”而不是“0”,以生成“更新跳过锁定”。这就是它在使用 JPA 时与 Hibernate 一起工作的方式。那么你想通过将它设置为 0 来达到什么目的呢? 我现在明白了。我不知何故没有看到您提到这种方式也是 Hibernate 特有的,即使在 JPA 设置中正式表达也是如此。我的错。删除了我之前的大部分 cmets。 呵呵,查询超时-2(适用于所有查询?)作为指标使用SKIP LOCKED?奇怪的想法。【参考方案2】:

我知道这篇文章有点老了,但为了记录,正如接受的答案所说,“javax.persistence.lock.timeout”(org.hibernate.cfg.AvailableSettings#JPA_LOCK_TIMEOUT)设置为“-2”(org.hibernate.LockOptions#SKIP_LOCKED)休眠导致“跳过锁定”。但是,这可以在运行时完成,而无需设置任何全局设置。

自从 2.0 JPA allows to pass hints 就这样

entityManager.find(MyType.class, id, LockModeType.PESSIMISTIC_WRITE, new HashMap<String, Object>() 
        put("javax.persistence.lock.timeout", "-2");
    );

【讨论】:

这是一种在 spring-data ***.com/questions/52058253/… 中实现的方法【参考方案3】:

对于spring JpaRepository,可以使用这个:

String SKIP_LOCKED = "-2";
@QueryHints(@QueryHint(name = AvailableSettings.JPA_LOCK_TIMEOUT, value = SKIP_LOCKED))
@Lock(LockModeType.PESSIMISTIC_WRITE)
List<YourEntity> fooBar();

在 Oracle 上运行良好,不确定其他人

【讨论】:

【参考方案4】:

Oracle 不提供读锁,因为它不需要;撤消日志使其变得不必要。所以,SELECT...FOR UPDATE 实际上只是 Oracle 的一个 WRITE 锁。

使用 JPA,您希望将 LockModeType 设置为 PESSIMISTIC_WRITE。

【讨论】:

这不是读取锁,它是您在读取时获得的更新锁。最终结果是其他更新阻塞但不读取。 @PawelZieminski 再次阅读了我的答案;我不是在说你认为我是什么。

以上是关于选择从 JPA 级别锁定的更新跳过的主要内容,如果未能解决你的问题,请参考以下文章

为啥在选择的更新跳过锁定时,若有的几个会话可以看到行?

如何在 postgres 中使用“更新跳过锁定”而不锁定查询中使用的所有表中的行?

Spring JPA 锁定概念

使用内连接进行查询的方法,用于更新 X 跳过锁定、排序和限制

JPA 锁定 PESSIMISTIC_WRITE 和 FEW 事务

插入和删除查询是不是可以从锁定等待超时中逃脱?