【发布时间】:2018-12-19 04:28:18
【问题描述】:
我有以下代码片段。在我调用BatchSettleService.batchSettleWork(Array.asList([1,2,3])) 之后。我发现账户余额在 DB 中只减少了 1。调试结果是每次accountRepository.findByIdForUpdate(2)返回原始Account,在过去的循环中没有任何改变。我试过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);
}
【问题讨论】:
-
@Gab 是的,我想防止并发读取。但我不清楚 PESSIMISTIC_READ 和 PESSIMISTIC_WRITE 之间的区别,所以我选择了严格的。感谢您的评论
-
PESSIMISTIC_READ 防止并发写入(共享锁)和 PESSIMISTIC_WRITE 也防止并发读取(独占锁)。你的编码方式确实需要排他锁
-
@Query("select ac from Account a where a.id = ?1")中难道没有错别字]
-
恕我直言,您的期望是正确的
-
@Gab 是的,我现在似乎很清楚区别。幸运的是我做出了正确的选择,哈哈。你能帮我研究一下这个案例吗?
标签: java hibernate transactions spring-data-jpa