Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring JPA无法在一个线程中正确处理多个事务_Java_Hibernate_Transactions_Spring Data Jpa - Fatal编程技术网

Java Spring JPA无法在一个线程中正确处理多个事务

Java Spring JPA无法在一个线程中正确处理多个事务,java,hibernate,transactions,spring-data-jpa,Java,Hibernate,Transactions,Spring Data Jpa,我有以下代码片段。调用BatchSettleService.batchSettleWork(Array.asList([1,2,3]))之后。我发现账户余额只减少了1分贝。调试结果是每次accountRepository.findByIdForUpdate(2)返回原始帐户时,不会对过去的循环进行任何更改。我已经尝试了Isolation.SERIALIZABLElevel,但结果是一样的。我使用的数据库是MySQL 5.7.20 InnoDb引擎。JPA实现是Hibernate。我希望账户余额减

我有以下代码片段。调用
BatchSettleService.batchSettleWork(Array.asList([1,2,3]))之后
。我发现账户余额只减少了1分贝。调试结果是每次
accountRepository.findByIdForUpdate(2)
返回原始帐户时,不会对过去的循环进行任何更改。我已经尝试了
Isolation.SERIALIZABLE
level,但结果是一样的。我使用的数据库是MySQL 5.7.20 InnoDb引擎。JPA实现是Hibernate。我希望账户余额减少3。我对交易的理解是否有问题?提前谢谢你

@Service
public class BatchSettleService {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private WorkSettleService workSettleService;

    public List<WorkSettleResponse> batchSettleWork(List<Long> workIds) {
        List<WorkSettleResponse> results= new ArrayList<>();
        for(Long workId:workIds) {
            try {
                results.add(workSettleService.settleWork(new WorkSettleRequest(workId)));
            } catch (WrappedException e) {
                results.add(new WorkSettleResponse(workId,e.getErrCode(),e.getMessage()));
                logger.error("Settle work failed for {}",workId,e);
            }
        }
        return results;
    }

}


   public class WorkSettleService{

        @Autowired
        private AccountRepository accountRepository;

        @Transactional(rollbackFor= {WorkSettleException.class,RuntimeException.class},propagation=Propagation.REQUIRES_NEW)
        public WorkSettleResponse settleWork(WorkSettleRequest req){
             Account account = accountRepository.findByIdForUpdate(2);
             Integer balance = account .getBalance();
             accountRepository.updateBalanceById(account.getId(),balance-1)
        }
    }


    public interface AccountRepository extends Repository<Account, Integer> {

        public Account findById(Integer id);

        @Lock(LockModeType.PESSIMISTIC_WRITE)
        @Query("select ac from Account a where a.id = ?1")
        public Account findByIdForUpdate(Integer id);

        @Modifying
        @Query("update Account a set a.balance = ?2 where a.id = ?1")
        public int updateBalanceById(Integer id,Integer balance);

}
@服务
公共类BatchSettleService{
私有记录器Logger=LoggerFactory.getLogger(getClass());
@自动连线
私人工作设置服务工作设置服务;
公共列表批处理结算工作(列表工作ID){
列表结果=新建ArrayList();
for(长工作ID:workIds){
试一试{
结果.add(workSettleService.settleWork(newworksettlerequest(workId)));
}捕获(包裹){
添加(新的工作设置响应(workId,e.getErrCode(),e.getMessage());
logger.error(“为{}解决工作失败”,工作ID,e);
}
}
返回结果;
}
}
公共类WorkSettleService{
@自动连线
私人帐户存储库;
@事务性(rollbackFor={WorkSettleException.class,RuntimeException.class},propagation=propagation.REQUIRES\u NEW)
公共工作设置响应结算工作(工作设置请求){
Account Account=accountRepository.findByIdForUpdate(2);
整数余额=account.getBalance();
accountRepository.updateBalanceById(account.getId(),balance-1)
}
}
公共接口AccountRepository扩展存储库{
公共帐户findById(整数id);
@锁(锁模式类型。悲观写入)
@查询(“从帐户a中选择ac,其中a.id=?1”)
公共帐户findByIdForUpdate(整数id);
@修改
@查询(“更新帐户a集合a.balance=?2,其中a.id=?1”)
public int updateBalanceById(整数id,整数余额);
}
这个案子已经解决了。 使用
account.setBalance(balance-1)
而不是
accountRepository.updateBalanceById(account.getId(),balance-1)

我不知道为什么
@Modifying
注释在
@Query
从EM缓存获取数据时不更新EM缓存,这是Spring JPA实现的一点限制。

@Gab是的,我想防止并发读取。但是我不清楚悲观的阅读和悲观的写作之间的区别,所以我选择了严格的。感谢您的评论悲观读防止并发写(共享锁)和悲观写防止并发读(独占锁)。您编写它的方式确实需要一个独占锁,@Query(“从帐户a中选择ac,其中a.id=?1”)中没有输入您的期望值correct@Gab是的,我现在觉得差别很明显。我幸运地做出了正确的选择,哈哈。你能帮我研究一下这个案子吗?