Redis高并发锁(二)乐观锁

本文介绍了如何使用Redis的watch、multi和exec命令实现乐观锁,通过一个示例展示了在并发更新库存时如何避免数据不一致。在业务改造部分,展示了StockService类的代码实现,但测试结果显示性能表现不佳,吞吐量仅为6,尽管成功解决了库存清零的问题。
摘要由CSDN通过智能技术生成

redis乐观锁

由watch multi exec配合实现乐观锁

1. watch 监控key

可以监控一个或者多个key的值,若在事务执行(exec)之前,key的值发生变化则取消事务执行

2. multi 开启事务

3. exec 执行事务

4. 演示

1) 先用两个连接AB访问redis

2) A监控key,此时库存是4501

在这里插入图片描述

3) A开启事务,并且将库存-1,事务进入队列等待执行

在这里插入图片描述

4)此时B更新库存为2001

在这里插入图片描述

5)A开始执行事务

在这里插入图片描述

执行为空,即执行失败,且库存已被B更新为了2001

6)若事务执行过程中没有被B执行呢
在这里插入图片描述
执行成功!!!

业务改造

1. StockService

@Service
public class StockService {

    @Autowired
    private StockMapper stockMapper;


    @Autowired
    private StringRedisTemplate redisTemplate;

    public void deduct() {

        redisTemplate.execute(new SessionCallback<Object>() {
            @Override
            public <K, V> Object execute(RedisOperations<K, V> redisOperations) throws DataAccessException {
                // watch 监控key
                redisOperations.watch((K) "stock");

                // 1。 查询库存
                String stockStr = redisTemplate.opsForValue().get("stock");
                if (!StringUtil.isNullOrEmpty(stockStr)) {
                    int stock = Integer.parseInt(stockStr);
                    // 2。 判断条件是否满足
                    if (stock > 0) {

                        // multi 开启事务
                        redisOperations.multi();
                        // 3 更新redis
                        redisTemplate.opsForValue().set("stock", String.valueOf(stock - 1));
                        // exec 执行事务
                        List<Object> list = redisOperations.exec();
                        // 如果执行事务返回结果为空,则重试
                        if (CollectionUtils.isEmpty(list)) {
                            try {
                                Thread.sleep(20);
                            } catch (InterruptedException e) {
                                throw new RuntimeException(e);
                            }
                            deduct();
                        }

                    }
                }
                return null;
            }
        });

    }
}

需要在redisTemplate.execute(new SessionCallback() {})的匿名内部类中实现redis事务。

而RedisOperations
在这里插入图片描述
其实就是我们使用的StringRedisTemplate,所以直接用它调用即可。

测试

在这里插入图片描述
性能太差了,吞吐量只有6

在这里插入图片描述
但库存成功清0了,问题解决

问题

性能太差

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

范大

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

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

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

打赏作者

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

抵扣说明:

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

余额充值