WATCH 机制:使用 WATCH 监视一个或多个 key , 跟踪 key 的 value 修改情况,如果有key 的 value 值在事务 EXEC 执行之前被修改了,整个事务被取消。EXEC 返回提示信息,表示
事务已经失败。
WATCH 机制使的事务 EXEC 变的有条件,事务只有在被 WATCH 的 key 没有修改的前提下才能执行。不满足条件,事务被取消。使用 WATCH 监视了一个带过期时间的键,那么即使这个键过期了,事务仍然可以正常执行.
大多数情况下,不同的客户端会访问不同的键,相互同时竞争同一 key 的情况一般都很少,watch 能很好解决数据冲突的问题。
①WATCH 命令可以被调用多次。对键的监视从 WATCH 执行之后开始生效,直到调用 EXEC 为止。不管事务是否成功执行,对所有键的监视都会被取消。
②当客户端断开连接时,该客户端对键的监视也会被取消。
③UNWATCH 命令可以手动取消对所有键的监视
在客户端A开启watch机制并开启事务插入数据,客户端B插入数据two,这时客户端A要提交事务的时候就出现nil.
思路:
- 利用redis的watch功能,监控这个redisKey的状态值
- 获取redisKey的值
- 创建redis事务
- 给这个key的值+1
- 然后去执行这个事务,如果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
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)