MySQL锁——一条更新语句处理并发
早睡蛋
# MySQL更新语句编写
我们首先分析一下原有代码的处理逻辑:
//1,查询库存
QueryWrapper<Stock> stockQueryWrapper = new QueryWrapper<>();
stockQueryWrapper.eq("product_code", "1001");
Stock stock = stockMapper.selectOne(stockQueryWrapper);
//2.判断库存是否充足
if (stock != null && stock.getCount() > 0) {
stock.setCount(stock.getCount() - 1);
//3.更新库存到数据库
stockMapper.updateById(stock);
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
我们可以使用一条更新的SQL语句,完成上述的三个步骤:
update db_stock set count = count - 1 where product_code = '1001' and count >=1;
1
这一条SQL语句是具备原子性的,因为update、delete、insert都是原子操作,都会加锁。
接下来我们在Dao层编写逻辑:
@Mapper
public interface StockMapper extends BaseMapper<Stock> {
@Update("update db_stock set count = count - #{count} where product_code = #{productCode} and count >= #{count}")
int updateStock(@Param("productCode") String productCode, @Param("count") Integer count);
}
1
2
3
4
5
6
7
2
3
4
5
6
7
最后我们的业务代码变为一行代码吧,并且需要把加锁的语句注释掉:
stockMapper.updateStock("1001",1);
1
我们还是在集群模式下进行压力测试,通过测试,我们查看数据库可以看出没有出现超卖现象,并发问题得以解决:
# 总结
使用MySQL锁(一条更新语句)可以解决三种JVM锁失效的问题
# 一条MySQL语句的优缺点
# 优点
能够有效地解决多例模式、事务、集群下JVM锁失效的问题
# 缺点
锁范围:
- 需要注意锁的范围
存在多个库存:
- 同一条商品可能在其他地区也有仓库,一条SQL会出现问题,因为在实际情况中,我们会根据算法计算出仓库发货优先的顺序
无法记录库存变化的前后状态