使用乐观锁更新mysql库存,保证数据一致性

- 技术笔记,巩固知识点

- 记录工作实战

一、背景

1.就像多线程更新同一临界资源,需要加CAS锁或Aync(synchronized、RentrantLock),保证数据安全

2.多个请求,修改同一条的mysql记录的某个数值,也需要加锁(mysql层次的乐观锁)

3.加同步锁:效率太低

4.不加锁:mysql 多版本控制机制,每个事务看到的都是自己的副本(就像多核cpu,每个核只能看到自己的缓存副本),会导致数据更新不一致问题

mysql 乐观锁实现

    /**
     * 乐观锁更新库存,库存不能为负数
     * @param id
     * @param stock 入参
     * @return
     * @author Administrator
     * @date 2024/5/28 17:50
     **/
    public void changeStockByIdWithVersion(Integer id, BigDecimal stock) {
        Assert.isTrue(stock.compareTo(BigDecimal.ZERO)>=0, "更新失败:欲更新库存为负数");
        TailoringStockManagementEndProductStock db = getById(id);
        boolean update = lambdaUpdate()
                .set(ProductStock::getPurchaseQuantity, stock)
                .set(ProductStock::getVersion, db.getVersion() + 1)
                .set(ProductStock::getUpdateBy, AuthUtil.getName())
                .set(TailoringStockManagementEndProductStock::getUpdateAt, LocalDateTime.now())
                .eq(ProductStock::getId, id)
                .eq(ProductStock::getVersion, db.getVersion())
                .update();
        Assert.isTrue(update, "更新失败:乐观锁未锁中,请重新操作");
    }

mysql 乐观锁原理论述

并发情况,事务A在获取原库存、计算最终库、执行sql之前,这段时间内,事务B已把库存修改提交,此时事务A再更新,会覆盖掉事务B的更新。

简单说,事务A开启时,拿到数据快照,相当于拿到了库存的副本。

要想保证数据更新,必须要保证在事务A期间,没有别的事务更新。也就是version没有变化。

在实现时,只需在执行sql之前获取一下version(同一个事务内,任何时候任何地方时候获取version都是一样的,简化实现,直接紧贴在更新sql前一行),作为更新条件。根据返回的true false 判断是否命中。false则要抛异常,通知用户重试

其它简单方案

使用分布式锁,将库存的id 作为key, 同一条库存同一时间只允许一个事务更新

  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值