如何在Spring Data JPA查询中指定@lock超时? [英] How to specify @lock timeout in spring data jpa query?
问题描述
如何为查询指定 @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:
-
EntityManager
或Query方法
之一的参数. -
@NamedQuery
批注中的设置. -
Persistence.createEntityManagerFactory
方法的参数. -
persistence.xml
部署描述符中的值.
- The argument to one of the
EntityManager
orQuery methods
. - The setting in the
@NamedQuery
annotation. - The argument to the
Persistence.createEntityManagerFactory
method. - 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.
- 如何启用LockModeType.使用Spring Data JPA查找实体时会出现PESSIMISTIC_WRITE?
- 如何向Spring Data JPA添加自定义方法
- 使用Postgres的Spring数据悲观锁超时
- 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 aPESSIMISTIC_WRITE
lock on that database object. - A
PESSIMISTIC_WRITE
lock request fails if another user currently holds either aPESSIMISTIC_WRITE
lock or aPESSIMISTIC_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);
资源链接:
这篇关于如何在Spring Data JPA查询中指定@lock超时?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!