基于springboot、tk.mybatis的库存并发扣减问题(幻读引起的库存未扣减问题)

基于Springboot \tk.mybatis\mysql数据库开发wms系统,并发出库引起的库存扣减问题。(并发扣减库存其中一个幻读(脏读)导致记账错误)

解决方案:1 单个应用(只部署一个节点的应用)系统考虑在扣减的方法上增加同步,使访问串行可解决此问题。
2 多几点部署的集群应用,考虑基于数据库锁机制来完成并发扣减。
我采用的的方案2,方案2中涉及到悲观锁和乐观锁两种方案,我选择的是乐观锁。简单备注下悲观和乐观锁的概念。白话解释下,悲观锁:对请求访问的对象比较悲观认为每次都有并发的现象出现都对记录进行锁定。常用的做法是在查询记录sql后追加 select for update ,保证其他线程不会出现脏读的现象。乐观锁:对请求的访问比较乐观,通常使用 version版本来实现。update TableA set qtp = :qtp ,set version = :version+1 where pk = :pk and version = :oldversion
tk.mybatis封装了@Version 注解,我需要做的在表中增加字段 Version 类型 int (注意给默认值 version 初始值为 0 ),实体bean对象增加属性version并增加tk的@Version注解(小技巧数据库中有默认值,实体bean对象定义时也需要赋初始值)Integer version = 0; 这样新增的时候默认就会有version了。
基于tk.mybatis 修改改动最小对生产环境影响最低和同事一起讨论后采用了此方案。希望后续有类似的问题的可以采纳。

那为什么不用redis呢

可以使用redis的incrby特性来扣减库存

既然想到用version了,为什么不用库存本身做条件呢?
希望对你有帮助,不喜勿喷,有用请采纳
@Update("UPDATE product SET lock_stock = lock_stock + #{buyNum} WHERE id = #{id} AND stock - lock_stock >= #{buyNum}")
int delStock(@Param("id") Long productId, @Param("buyNum") Integer buyNum);