Spring Boot下具有并发JPA更新的OptimisticLockException

时间:2015-03-03 19:06:56

标签: jpa optimistic-locking pessimistic-locking

以下是the sample project,其中再现了例外情况。

此示例说明了许多并发事务正在修改帐户余额时的问题。帐户可以绑定许多卡实体。交易与订单和最后的订单有关。每个Thread执行如下:

  1. 客户请求' / order / {hashId}'对于第一个可用的订单卡哈希ID订单
  2. 客户为给定订单启动新tx - ' / tx / {orderId} / start'
  3. 客户端完成tx - ' / tx / {txId} / stop / {amount}'从帐户余额中减去tx金额。
  4. 实体锁定

    帐户和订单实体的版本为@ javax.persistence.Version。在最后一步中,使用悲观写锁定来锁定帐户实体:

    @Override
    public Account getLockedAccount(Integer id) {
        final Account account = findOne(id);
        em.lock(account, LockModeType.PESSIMISTIC_WRITE);
        return account;
    }
    

    测试

    要测试并发访问,请使用JMeter脚本src / main / resources / StressTest.jmx。注意:由于Extra libs的使用,必须将JSON Path extractor安装到JMeter home以运行脚本。通过普通笔记本电脑上的这些特定设置,您可以获得大约10%的TxEnd请求错误:

    {  
    "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 :使用任务执行程序的工作放在another branch中。 Spring ThreadPoolTaskExecutor与事务性任务相结合可以解决问题。

1 个答案:

答案 0 :(得分:0)

在查找和锁定之间,可能已经修改了Account对象。 你需要在一个声明中做到这一点

EM.find(Account.class,id,LockModeType.PESSIMISTIC_WRITE)