要悲观地锁定实体,请将锁定模式设置为 、 或 。PESSIMISTIC_READ
PESSIMISTIC_WRITE
PESSIMISTIC_FORCE_INCREMENT
如果无法获得悲观锁,但锁定失败不会导致事务回滚,则会引发 。LockTimeoutException
悲观锁定超时
可以使用 javax.persistence.lock.timeout 属性指定持久性提供程序在数据库表上获取锁定时应等待的时间长度(以毫秒为单位)。如果获取锁所需的时间超过此属性的值,则将引发 a,但当前事务不会标记为回滚。如果此属性设置为 0,则持久性提供程序在无法立即获取锁时应引发 LockTimeoutException
。LockTimeoutException
如果在多个位置设置了 ,则该值将按以下顺序确定:javax.persistence.lock.timeout
- 或 之一的参数。
EntityManager
Query methods
- 批注中的设置。
@NamedQuery
- 方法的参数。
Persistence.createEntityManagerFactory
- 部署描述符中的值。
persistence.xml
对于弹簧数据 1.6 或更高版本
@Lock
从Spring Data JPA的1.6版本开始,CRUD方法就受支持了(事实上,已经有一个里程碑可用)。有关更多详细信息,请参阅此票证。
使用该版本,您只需声明以下内容:
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);
您可以创建一些具有成员变量的静态锁定管理器,然后将一个方面包裹在每个存储库中的每个方法上,这些方法调用bindResource,并在ThreadLocal中设置了锁定模式。这将允许您基于每个线程设置锁定模式。然后,您可以创建自己的注释,它将方法包装在一个方面中,该方面在运行方法之前设置特定于线程的锁定模式,并在运行方法后清除它。ThreadLocal<LockMode>
@MethodLockMode
资源链接:
- 如何使用Spring Data JPA查找实体时启用LockModeType.PESSIMISTIC_WRITE?
- 如何将自定义方法添加到Spring Data JPA
- 春季数据悲观锁定超时与Postgres
- JPA Query API
悲观锁定超时的各种示例
设置悲观锁定
实体对象可以通过 lock 方法显式锁定:
em.lock(employee, LockModeType.PESSIMISTIC_WRITE);
第一个参数是实体对象。第二个参数是请求的锁定模式。
如果在调用 lock 时没有活动事务,则会引发 A,因为显式锁定需要活动事务。TransactionRequiredException
如果无法授予请求的悲观锁,则抛出 A:LockTimeoutException
- 如果另一个用户(由另一个 EntityManager 实例表示)当前持有该数据库对象上的锁定,则锁定请求将失败。
PESSIMISTIC_READ
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);
对于实体管理器 - 使用以下方法: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);
资源链接:
- 锁定在 JPA 中
- 悲观锁定超时