Mysql分布式锁(四)乐观锁实现并发

CAS - Compare And Swap

先比较再交换,一般通过时间戳或者version版本号。
举例:先查询后更新,在数据更新前,先比较数据库中的版本号是否与之前查询的时候一致,若一致则更新,不一致则重新尝试业务。

业务改造

1. 表结构新增version列

在这里插入图片描述

2. 修改代码

Stock

@TableName("db_stock")
@Data
public class Stock {
    private Long id;
    private String productCode;
    private String warehouse;
    private Integer count;
    private Integer version;
}

StockService

@Service
public class StockService {

    @Autowired
    private StockMapper stockMapper;

    /**
     * 乐观锁
     */
    // @Transactional 将事务注释掉,因为update操作mysql会自动添加事务,降低了事务的粒度,防止事务超时报错
    public void deduct() {
        // 1。 查询库存
        List<Stock> list = stockMapper.selectList(new QueryWrapper<Stock>().eq("product_code", "1001"));

        // 2。 判断条件是否满足
        if (!CollectionUtils.isEmpty(list)) {
            // 假设就拿第一个北京仓的
            Stock stock = list.get(0);
            if (stock != null && stock.getCount() > 0) {
                // 3。 更新库存
                Integer version = stock.getVersion();
                ;
                stock.setCount(stock.getCount() - 1);
                stock.setVersion(version + 1);

                if (stockMapper.update(stock, new UpdateWrapper<Stock>().eq("id", stock.getId()).eq("version", version)) == 0) {
                    // 如果没有更新成功,则重试
                    try {
                        Thread.sleep(20); // 等待20ms。防止太多重试,导致栈溢出
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    this.deduct(); // 递归调用,重试
                }

            }
        }
    }

}

注意两个细节:

  1. Transactional 事务注解注释掉
    update操作mysql会自动加锁,降低了事务粒度,防止事务超时报错
  2. Thread.sleep(20); 失败后睡眠20ms
    防止太多重试,导致栈溢出

3. 测试

在这里插入图片描述
吞吐量小的可怜,只有7

在这里插入图片描述
数据库成功清0,业务没有问题。

问题

1. 高并发情况下,性能极低

会有很多请求重复的去尝试,随着请求越来越多,吞吐量越来越差。

2. ABA问题

A -> B -> A,你之前查询的时候拿到的是A, 然后更新前查询还是A,你以为它一直没有修改,其实它偷偷改了多少次你都不知道。

3. 读写分离情况下导致乐观锁不可靠

读写分离下,读写是分别的库,两个库的数据更新有延迟,拿到的一直都只会是旧数据。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

范大

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值