使用Redis+Lua脚本实现分布式锁
1.1加锁// 1. 从redis中获取锁,set k1 v1 px 20000 nxString uuid = UUID.randomUUID().toString();Boolean lock = this.redisTemplate.opsForValue().setIfAbsent("lock", uuid, 2, TimeUnit.SECONDS);使用Lua释放锁// 2. 释放锁 d
·
1.1加锁
// 1. 从redis中获取锁,set k1 v1 px 20000 nx
String uuid = UUID.randomUUID().toString();
Boolean lock = this.redisTemplate.opsForValue().setIfAbsent("lock", uuid, 2, TimeUnit.SECONDS);
使用Lua释放锁
// 2. 释放锁 del
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
// 设置lua脚本返回的数据类型
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
// 设置lua脚本返回类型为Long
redisScript.setResultType(Long.class);
redisScript.setScriptText(script);
redisTemplate.execute(redisScript, Arrays.asList("lock"),uuid);
重试
Thread.sleep(500);
testLock();
使用案例
public void testLock() {
// 使用uuid防止误删锁
String uuid = UUID.randomUUID().toString();
// 从Redis获取锁
Boolean flag = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 3, TimeUnit.SECONDS);
if (flag){
// flag = true:表示拿到锁! 执行业务逻辑
// 从缓存中获取数据
String num = redisTemplate.opsForValue().get("num");
// 判断,缓存为空则直接返回
if (StringUtils.isEmpty(num)){
return;
}
// num不为空,需要对当前值进行+1操作,写会缓存
int numValue = Integer.parseInt(num);
// 写回缓存
redisTemplate.opsForValue().set("num",String.valueOf(++numValue));
// 定义一个lua脚本
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
// 创建对象
DefaultRedisScript<Long> redisScript = new DefaultRedisScript();
// 设置lua脚本
redisScript.setScriptText(script);
//设置lua脚本返回类型为Long
redisScript.setResultType(Long.class);
// redis调用lua脚本
redisTemplate.execute(redisScript, Arrays.asList("lock"),uuid);
} else {
// 没有获取到锁
try {
//睡眠
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 自旋
testLock();
}
}
更多推荐
已为社区贡献1条内容
所有评论(0)