如何指定@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
, orPESSIMISTIC_FORCE_INCREMENT
.If a pessimistic lock cannot be obtained, but the locking failure doesn’t result in a transaction rollback, a
LockTimeoutException
is thrown.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 aLockTimeoutException
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:
- 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 或更高版本
@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
将方法包装在一个方面的注释,该方面在运行方法之前设置特定于线程的锁定模式,并在运行方法后清除它。
资源链接:
- How to enable LockModeType.PESSIMISTIC_WRITE when looking up entities with Spring Data JPA?
- How to add custom method to Spring Data JPA
- Spring Data Pessimistic Lock timeout with Postgres
- 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);
资源链接:
关于java - 如何在spring data jpa查询中指定@lock超时?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29765934/