如何在spring数据jpa查询中指定@lock timeout?

use*_*759 17 java oracle spring hibernate jpa

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

我定义了这样的方法,

@Lock(LockModeType.PESSIMISTIC_WRITE)
Stock findById(String id);
Run Code Online (Sandbox Code Playgroud)

它似乎永远锁定.我开始javax.persistence.lock.timeout=0LocalContainerEntityManagerFactoryBean.jpaProperties,但没有受到影响.

Sky*_*ker 17

要悲观锁定机构,设置锁定模式 PESSIMISTIC_READ,PESSIMISTIC_WRITEPESSIMISTIC_FORCE_INCREMENT.

如果无法获得悲观锁定,但锁定失败不会导致事务回滚,LockTimeoutException则抛出a.

悲观的锁定超时

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

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

  1. 其中一个EntityManager或的论点Query methods.
  2. @NamedQuery注释中的设置.
  3. Persistence.createEntityManagerFactory方法的论据.
  4. persistence.xml部署描述符中的值.

对于Spring Data 1.6或更高版本

@Lock从Spring Data JPA 1.6版本开始,CRUD方法支持(事实上,已经有一个里程碑可用).有关详细信息,请参阅此票证.

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

interface WidgetRepository extends Repository<Widget, Long> {

  @Lock(LockModeType.PESSIMISTIC_WRITE)
  Widget findOne(Long id);
}
Run Code Online (Sandbox Code Playgroud)

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

另一方面,

对于早期版本的Spring Data 1.6

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

如果你想实现自己的解决方案,你可能会.在引擎盖下@Lock处理注释,通过LockModePopulatingMethodIntercceptor该注释执行以下操作:

TransactionSynchronizationManager.bindResource(method, lockMode == null ? NULL : lockMode);
Run Code Online (Sandbox Code Playgroud)

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

资源链接:

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

悲观锁超时的各种例子

设置悲观锁定

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

em.lock(employee, LockModeType.PESSIMISTIC_WRITE);
Run Code Online (Sandbox Code Playgroud)

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

TransactionRequiredException如果在调用lock时没有活动事务,则抛出A,因为显式锁定需要活动事务.

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

  • PESSIMISTIC_READ如果另一个用户(这是由另一EntityManager实例表示)当前持有的锁请求失败 PESSIMISTIC_WRITE该数据库对象上的锁.
  • PESSIMISTIC_WRITE如果另一用户当前持有任一个锁定请求失败PESSIMISTIC_WRITE锁或PESSIMISTIC_READ该数据库对象上的锁.

设置查询提示(范围)

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

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

<properties>
   <property name="javax.persistence.query.timeout" value="3000"/>
</properties>
Run Code Online (Sandbox Code Playgroud)

对于EntityManagerFactory - 使用createEntityManagerFacotory方法:

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

对于EntityManager - 使用createEntityManager方法:

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

或使用setProperty方法:

em.setProperty("javax.persistence.query.timeout", 6000);
Run Code Online (Sandbox Code Playgroud)

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

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

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

query.setHint("javax.persistence.query.timeout", 8000);
Run Code Online (Sandbox Code Playgroud)

资源链接:

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


Dra*_*vic 9

您可以@QueryHints在Spring Data中使用:

@Lock(LockModeType.PESSIMISTIC_WRITE)
@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value ="5000")})
Stock findById(String id)
Run Code Online (Sandbox Code Playgroud)

  • 我正在尝试这个。第一个事务能够获取锁并在释放锁之前进行一些处理。同时,当第二个事务到来并尝试获取锁时,它似乎没有等待 value 属性中定义的时间(在您的示例中为 5000 毫秒),而是立即抛出异常“无法提取 ResultSet; SQL [ n/a];嵌套异常是 org.hibernate.exception.LockAcquisitionException:无法提取 ResultSet” (2认同)