OptimisticLockException与Spring引导下的并发JPA更新
这里是例外重现的地方 此示例说明了当许多并发事务正在修改帐户余额时的问题。帐户可以绑定多个卡实体。交易与订单和最后一次相关。每个线程执行如下操作:OptimisticLockException与Spring引导下的并发JPA更新,jpa,optimistic-locking,pessimistic-locking,Jpa,Optimistic Locking,Pessimistic Locking,这里是例外重现的地方 此示例说明了当许多并发事务正在修改帐户余额时的问题。帐户可以绑定多个卡实体。交易与订单和最后一次相关。每个线程执行如下操作: 客户端根据给定的卡哈希id请求“/order/{hashId}”以获取第一个可用订单 客户端为给定订单启动新的发送-'/tx/{orderId}/start' 客户端完成tx-'/tx/{txId}/stop/{amount}',其中tx金额从帐户余额中减去 实体锁定 帐户和订单实体的版本为@javax.persistence.Version。在最后
@Override
public Account getLockedAccount(Integer id) {
final Account account = findOne(id);
em.lock(account, LockModeType.PESSIMISTIC_WRITE);
return account;
}
测试
要测试并发访问,请使用脚本src/main/resources/StressTest.jmx。注意:由于使用了,必须安装到JMeter home才能运行脚本。在普通笔记本电脑上使用这些特定设置,您可以获得TxEnd请求约10%的错误:
{
"timestamp":1425407408204,
"status":500,
"error":"Internal Server Error",
"exception":"org.springframework.orm.ObjectOptimisticLockingFailureException",
"message":"Object of class [sample.data.jpa.domain.Account] with identifier [1]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [sample.data.jpa.domain.Account#1]",
"path":"/tx/1443/stop/46.4"
}
问题
尽管使用了悲观写锁,我仍然得到乐观锁异常。是否有其他方法可以确保帐户的完整性,而无需为所有更新或同步方法创建任务执行队列
UPD:与任务执行器的变通操作被置于。Spring
ThreadPoolTaskExecutor
与事务性任务相结合可以解决此问题。在查找和锁定之间,帐户对象可能已被修改。
你需要用一句话来表达
EM.find(Account.class,id,LockModeType.悲观写入)在使用EntityManager之前,我尝试了@Lock注释:
@Lock(LockModeType.悲观写入)Account findOne(整数)代码>。可以找到以前版本的完整实现。在Spring SimpleParepository中,当提示是当前LockModeType时,使用相同的等价物em.find(domainType,id,type,Hits)
。