WATCH 机制原理:

WATCH 机制:使用 WATCH 监视一个或多个 key , 跟踪 key 的 value 修改情况,如果有key 的 value 值在事务 EXEC 执行之前被修改了,整个事务被取消。EXEC 返回提示信息,表示
事务已经失败。
WATCH 机制使的事务 EXEC 变的有条件,事务只有在被 WATCH 的 key 没有修改的前提下才能执行。不满足条件,事务被取消。使用 WATCH 监视了一个带过期时间的键,那么即使这个键过期了,事务仍然可以正常执行.
大多数情况下,不同的客户端会访问不同的键,相互同时竞争同一 key 的情况一般都很少,watch 能很好解决数据冲突的问题。
在这里插入图片描述

取消watch机制#

①WATCH 命令可以被调用多次。对键的监视从 WATCH 执行之后开始生效,直到调用 EXEC 为止。不管事务是否成功执行,对所有键的监视都会被取消。
②当客户端断开连接时,该客户端对键的监视也会被取消。
③UNWATCH 命令可以手动取消对所有键的监视
在这里插入图片描述
在客户端A开启watch机制并开启事务插入数据,客户端B插入数据two,这时客户端A要提交事务的时候就出现nil.

用Watch机制实现秒杀

思路:

  1. 利用redis的watch功能,监控这个redisKey的状态值
  2. 获取redisKey的值
  3. 创建redis事务
  4. 给这个key的值+1
  5. 然后去执行这个事务,如果key的值被修改过则回滚,key不加1

实现代码:

public static void main(String[] arg) {
        String redisKey = "lock";
        ExecutorService executorService = Executors.newFixedThreadPool(20);//20个线程
        try {//初始化
            Jedis jedis = new Jedis("127.0.0.1", 6379);
            // 初始值
            jedis.set(redisKey, "0");
            jedis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        for (int i = 0; i < 1000; i++) {//尝试1000次
            executorService.execute(() -> {
                Jedis jedis1 = new Jedis("127.0.0.1", 6379);
                try {
                    jedis1.watch(redisKey);
                    String redisValue = jedis1.get(redisKey);
                    int valInteger = Integer.valueOf(redisValue);
                    String userInfo = UUID.randomUUID().toString();
                    // 没有秒完
                    if (valInteger < 20) {//redisKey
                        Transaction tx = jedis1.multi();//开启事务
                        tx.incr(redisKey);//自增
                        List list = tx.exec();//提交事务,如果返回nil则说明执行失败,因为我watch了的,只要执行失败,则
                        // 进来发现东西还有,秒杀成功
                        if (list != null && list.size() > 0) {
                            System.out.println("用户:" + userInfo + ",秒杀成功!当前成功人数:" + (valInteger + 1));
                        }else {//执行结果不是OK,说明被修改了,被别人抢了
                            System.out.println("用户:" + userInfo + ",秒杀失败");
                        }
                    }else {//东西秒完了
                        System.out.println("已经有20人秒杀成功,秒杀结束");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {//关闭redis
                    jedis1.close();
                }
            });
        }
        executorService.shutdown();//关闭线程池
    }

执行结果:
在这里插入图片描述

参考链接

  • https://www.cnblogs.com/IamHzc/p/15229701.html
  • https://blog.csdn.net/chengh1993/article/details/112685774
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐