我有以下代码片段。在我调用BatchSettleService.batchSettleWork(Array.asList([1,2,3]))
之后。我发现帐户余额仅减少1(DB)。调试结果是每次accountRepository.findByIdForUpdate(2)
返回原始帐户时,在过去的循环中未进行任何更改。我尝试过Isolation.SERIALIZABLE
级,但结果是相同的。我正在使用的数据库是MySQL 5.7.20 InnoDb Engine。 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);
}
答案 0 :(得分:0)
此案已解决。
使用account.setBalance(balance-1)
代替accountRepository.updateBalanceById(account.getId(),balance-1)
。
我不知道为什么@Modifying
注释不更新EM缓存,而@Query
从EM缓存中获取数据,这对于Spring JPA实现来说有点麻烦。