项目背景
优惠券数量有限,多个用户同时获取优惠券需要考虑并发问题,这里我采用的是CAS算法来实现。
框架
- springboot
- jpa
核心代码
@Transactional(rollbackOn = Exception.class)
public void buy2(String name, int buyQuantity) {
Product product = otherService.getByName(name);
int result = reduceStorage(buyQuantity, product);
// 模拟处理业务时间
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
while (result == 0) {
// 如果失败一直重试
Product pd = otherService.getByName(name);
if (product.getQuantity() > buyQuantity) {
result = reduceStorage(buyQuantity, pd);
} else {
System.out.println("库存不足");
return;
}
}
}
@Modifying
@Query("update Product roduct set quantity = ?2 where id = ?1 and quantity = ?3 and ?2 > 0")
int updateQuantity(int id, int newQuantity, int oldQuantity);
说明:
- 重新查询数据库时,必须确保能够读取到其他事务提交的数据,要求数据库的事务隔离级别至少是read committed(读已提交)
- 另外因为这里是内部方法调用,必须考虑spring事务传播机制,需要用到注解@Transactional(Transactional.TxType.NOT_SUPPORTED),意思是不支持spring事务传播,也就是说这个方法是一个单独的事务
- 另外一点是同一个bean内单独事务不生效,所以要把这个方法提取到其他bean中。
补充:
oracle数据库默认事务隔离级别:READ_COMMITTED
mysql数据库默认事务隔离级别:REPEATABLE_READ
mysql的隔离级别比oracle高
参考链接
https://blog.csdn.net/qq315737546/article/details/76850173
https://www.cnblogs.com/yougewe/p/7466677.html
完整源码地址
https://github.com/hejiancao/ThreadSummary