java - 如何在spring data jpa查询中指定@lock超时?

标签 java spring oracle hibernate jpa

如何指定@Lock查询超时时间? 我正在使用 Oracle 11g,我希望我可以使用类似 'select id from table where id = ?1 for update wait 5' 之类的东西。

我这样定义方法:

@Lock(LockModeType.PESSIMISTIC_WRITE)
Stock findById(String id);

它似乎永远锁定。 当我在 LocalContainerEntityManagerFactoryBean.jpaProperties 中设置 javax.persistence.lock.timeout=0 时,没有任何效果。

最佳答案

To lock entities pessimistically, set the lock mode to PESSIMISTIC_READ, PESSIMISTIC_WRITE, or PESSIMISTIC_FORCE_INCREMENT.

If a pessimistic lock cannot be obtained, but the locking failure doesn’t result in a transaction rollback, a LockTimeoutException is thrown.

Pessimistic Locking Timeouts

The length of time in milliseconds the persistence provider should wait to obtain a lock on the database tables may be specified using the javax.persistence.lock.timeout property. If the time it takes to obtain a lock exceeds the value of this property, a LockTimeoutException will be thrown, but the current transaction will not be marked for rollback. If this property is set to 0, the persistence provider should throw a LockTimeoutException if it cannot immediately obtain a lock.

If javax.persistence.lock.timeout is set in multiple places, the value will be determined in the following order:

  1. The argument to one of the EntityManager or Query methods.
  2. The setting in the @NamedQuery annotation.
  3. The argument to the Persistence.createEntityManagerFactory method.
  4. The value in the persistence.xml deployment descriptor.

对于 Spring Data 1.6 或更高版本

@Lock从 Spring Data JPA 1.6 版开始,CRUD 方法支持(事实上,已经有 milestone 可用)。看到这个ticket了解更多详情。

使用该版本,您只需声明以下内容:

interface WidgetRepository extends Repository<Widget, Long> {

  @Lock(LockModeType.PESSIMISTIC_WRITE)
  Widget findOne(Long id);
}

这将导致后备存储库代理的 CRUD 实现部分将配置的 LockModeType 应用到 find(…)调用EntityManager .

另一方面,

对于之前版本的 Spring Data 1.6

Spring Data 悲观@Lock注释仅适用于(如您所指出的)查询。我知道没有注释会影响整个事务。您可以创建 findByOnePessimistic调用 findByOne 的方法用悲观锁或者你可以改变findByOne总是获得一个悲观锁。

如果您想实现自己的解决方案,您可能可以。在引擎盖下 @Lock注释由 LockModePopulatingMethodIntercceptor 处理它执行以下操作:

TransactionSynchronizationManager.bindResource(method, lockMode == null ? NULL : lockMode);

您可以创建一些具有 ThreadLocal<LockMode> 的静态锁管理器。成员变量,然后在每个存储库中的每个方法周围都有一个方面,这些方法调用 bindResource 并在 ThreadLocal 中设置锁定模式。这将允许您在每个线程的基础上设置锁定模式。然后您可以创建自己的@MethodLockMode将方法包装在一个方面的注释,该方面在运行方法之前设置特定于线程的锁定模式,并在运行方法后清除它。

资源链接:

  1. How to enable LockModeType.PESSIMISTIC_WRITE when looking up entities with Spring Data JPA?
  2. How to add custom method to Spring Data JPA
  3. Spring Data Pessimistic Lock timeout with Postgres
  4. JPA Query API

悲观锁超时的各种例子

设置悲观锁

一个实体对象可以通过lock方法显式锁定:

em.lock(employee, LockModeType.PESSIMISTIC_WRITE);

第一个参数是一个实体对象。第二个参数是请求的锁定模式。

一个 TransactionRequiredException如果在调用 lock 时没有 Activity 事务,则抛出此错误,因为显式锁定需要 Activity 事务。

一个 LockTimeoutException如果请求的悲观锁不能被授予,则抛出:

  • 一个 PESSIMISTIC_READ如果另一个用户(即 由另一个 EntityManager 实例表示)当前持有一个 PESSIMISTIC_WRITE锁定该数据库对象。
  • 一个 PESSIMISTIC_WRITE如果当前有其他用户,则锁定请求失败 持有 PESSIMISTIC_WRITE锁或 PESSIMISTIC_READ锁上 该数据库对象。

设置查询提示(范围)

可以在以下范围(从全局到本地)设置查询提示:

对于整个持久性单元 - 使用 persistence.xml属性:

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

对于 EntityManagerFactory - 使用 createEntityManagerFacotory方法:

Map<String,Object> properties = new HashMap();
properties.put("javax.persistence.query.timeout", 4000);
EntityManagerFactory emf =
  Persistence.createEntityManagerFactory("pu", properties);

对于 EntityManager - 使用 createEntityManager方法:

Map<String,Object> properties = new HashMap();
properties.put("javax.persistence.query.timeout", 5000);
EntityManager em = emf.createEntityManager(properties);

或使用 setProperty 方法:

em.setProperty("javax.persistence.query.timeout", 6000);

对于 named query定义 - 使用 hints元素:

@NamedQuery(name="Country.findAll", query="SELECT c FROM Country c",
    hints={@QueryHint(name="javax.persistence.query.timeout", value="7000")})

对于特定的查询执行 - 使用 setHint方法(查询执行前):

query.setHint("javax.persistence.query.timeout", 8000);

资源链接:

  1. Locking in JPA
  2. Pessimistic Lock Timeout

关于java - 如何在spring data jpa查询中指定@lock超时?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29765934/

相关文章:

java - 检查列表类在java中是什么类型

java - 无法使用私有(private)变量对非静态字段 memberVariable 进行静态引用

sql - 如何将嵌套表展平为新行?

java - 匿名 plsql block 中的列索引无效

java - 如何在 Spring Maven 中通过 Junit 测试获取 Spring 配置

java - 根据解决方案制定数独谜题

java - 在 Spring Boot 服务上运行有限数量的线程

java - 从 Spring 应用程序中的 jar 中读取 log4j.xml

Spring MVC 在 session 中保存用户数据

oracle - 使用特定表名的Oracle View 列表