Spring Data JPA 解决秒杀系统中减库存操作
之前更新库存逻辑是先拿到 Goods 对象,然后将库存设置为当前库存减1,然后调用 GoodsRepository.save() 方法保存更新后的对象。这个处理逻辑会导致超售。
先上部分控制逻辑代码:
Goods goods = goodsRepository.findById(id).get(); goods.setNumber(goods.getNumber() - 1); if (goods.getNumber() <= 0) {throw new SeckillException(ResultEnum.END); } goodsRepository.save(goods);
新的方法是使用 @Transactional 注解管理事务和 @Query 注解自定义查询方法。
首先在 GoodsRepository 接口中定义一个减库存方法:
@Transactional @Modifying(clearAutomatically = true) @Query(value = "update Goods set number = number -1 where id=?1 and number>0") int reduceStock(Integer id);
要注意的几点是:
1.@Transactional 注解要使用 org.springframework.transaction.annotation.Transactional 包下的。( javax.transaction.Transactional 包下的一般是JAVA EE项目使用)
2.@Query 注解中 nativeQuery 项默认为 false,代表使用 JPQL 语句查询。nativeQuery = true 代表使用原生 SQL 语句查询。 下面两段代码功能一致:
@Query(value = "update Goods set number = number -1 where id=?1 and number>0") @Query(value = "update goods set number = number -1 where id=?1 and number>0",nativeQuery = true)
然后逻辑代码可以更新为:
Goods goods = goodsRepository.findById(id).get();
int state = reduceStock(id);
if(state != 0){
//保存订单
}
更新代码后测试未出现超售现象。
参考链接:
https://www.ibm.com/developerworks/cn/java/j-master-spring-transactional-use/index.html
https://www.oracle.com/technetwork/articles/vasiliev-jpql-085775-zhs.html?printOnly=1
https://zhuanlan.zhihu.com/p/29611306
https://blog.csdn.net/zt15732625878/article/details/78378995