如何在Spring Data JPA查询中指定@lock超时? [英] How to specify @lock timeout in spring data jpa query?

查看:210
本文介绍了如何在Spring Data JPA查询中指定@lock超时?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何为查询指定 @Lock 超时?我正在使用Oracle 11g,希望可以使用'从表中选择id,其中id =?1进行更新等待5'.

How to specify @Lock timeout for query? I am using Oracle 11g, I hope I can use something like '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 时,没有任何效果.

It seems to lock forever. When I set javax.persistence.lock.timeout=0 in LocalContainerEntityManagerFactoryBean.jpaProperties, there is no effect.

推荐答案

要悲观地锁定实体,请将锁定模式设置为 PESSIMISTIC_READ PESSIMISTIC_WRITE PESSIMISTIC_FORCE_INCREMENT .

如果无法获得悲观锁,但是锁失败不会导致交易回滚,因此 LockTimeoutException 抛出.

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

悲观的锁定超时

持久性提供程序应以毫秒为单位的时间长度等待获取对数据库表的锁定可能使用javax.persistence.lock.timeout属性.如果花费时间获得一个超过此属性值的锁, LockTimeoutException 将被抛出,但是当前事务不会被标记为回滚.如果此属性设置为0,则持久性提供程序应该抛出一个 LockTimeoutException 无法立即获取锁.

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.

如果在多个位置设置了 javax.persistence.lock.timeout ,则值将按以下顺序确定:

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

  1. EntityManager Query方法之一的参数.
  2. @NamedQuery 批注中的设置.
  3. Persistence.createEntityManagerFactory 方法的参数.
  4. persistence.xml 部署描述符中的值.
  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或更高版本

从Spring Data JPA 1.6版开始,CRUD方法支持

@Lock (实际上,已经有一个门票.

For Spring Data 1.6 or greater

@Lock is supported on CRUD methods as of version 1.6 of Spring Data JPA (in fact, there's already a milestone available). See this ticket for more details.

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

With that version you simply declare the following:

interface WidgetRepository extends Repository<Widget, Long> {

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

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

This will cause the CRUD implementation part of the backing repository proxy to apply the configured LockModeType to the find(…) call on the EntityManager.

Spring Data悲观的 @Lock 批注仅适用于(如您所指出的)查询.我知道没有注释会影响整个交易.您可以创建 findByOnePessimistic 方法并使用悲观锁来调用 findByOne ,也可以更改 findByOne 以始终获得悲观锁.

The Spring Data pessimistic @Lock annotations only apply (as you pointed out) to queries. There are not annotations I know of which can affect an entire transaction. You can either create a findByOnePessimistic method which calls findByOne with a pessimistic lock or you can change findByOne to always obtain a pessimistic lock.

如果您想实施自己的解决方案,则可能可以.在 @Lock 注释下,由 LockModePopulatingMethodIntercceptor 处理,该操作执行以下操作:

If you wanted to implement your own solution you probably could. Under the hood the @Lock annotation is processed by LockModePopulatingMethodIntercceptor which does the following:

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

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

You could create some static lock manager which had a ThreadLocal<LockMode> member variable and then have an aspect wrapped around every method in every repository which called bindResource with the lock mode set in the ThreadLocal. This would allow you to set the lock mode on a per-thread basis. You could then create your own @MethodLockMode annotation which would wrap the method in an aspect which sets the thread-specific lock mode before running the method and clears it after running the method.

  1. 如何启用LockModeType.使用Spring Data JPA查找实体时会出现PESSIMISTIC_WRITE?
  2. 如何向Spring Data JPA添加自定义方法
  3. 使用Postgres的Spring数据悲观锁超时
  4. JPA查询API


悲观锁超时的各种示例

设置悲观锁

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


Various Example of Pessimistic Lock Timeout

Setting a Pessimistic Lock

An entity object can be locked explicitly by the lock method:

em.lock(employee, LockModeType.PESSIMISTIC_WRITE);

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

The first argument is an entity object. The second argument is the requested lock mode.

如果由于显式锁定需要活动事务而调用锁时没有活动事务,则抛出 TransactionRequiredException .

A TransactionRequiredException is thrown if there is no active transaction when lock is called because explicit locking requires an active transaction.

如果无法授予所请求的悲观锁,则会抛出 LockTimeoutException :

A LockTimeoutException is thrown if the requested pessimistic lock cannot be granted:

  • 如果另一个用户(即由另一个EntityManager实例表示)目前持有 PESSIMISTIC_WRITE 锁定该数据库对象.
  • 如果另一个用户当前正在 PESSIMISTIC_WRITE 锁定请求失败持有 PESSIMISTIC_WRITE 锁或 PESSIMISTIC_READ 锁该数据库对象.
  • A PESSIMISTIC_READ lock request fails if another user (which is represented by another EntityManager instance) currently holds a PESSIMISTIC_WRITE lock on that database object.
  • A PESSIMISTIC_WRITE lock request fails if another user currently holds either a PESSIMISTIC_WRITE lock or a PESSIMISTIC_READ lock on that database object.

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

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

For the entire persistence unit - using a persistence.xml property:

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

对于EntityManagerFactory-使用 createEntityManagerFacotory 方法:

For an EntityManagerFactory - using the createEntityManagerFacotory method:

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

对于EntityManager-使用 createEntityManager 方法:

For an EntityManager - using the createEntityManager method:

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

或使用setProperty方法:

or using the setProperty method:

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

对于命名查询定义-使用提示元素:

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

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

For a specific query execution - using the setHint method (before query execution):

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

资源链接:

  1. 锁定JPA
  2. 悲观锁定超时

这篇关于如何在Spring Data JPA查询中指定@lock超时?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆