本文共 2149 字,大约阅读时间需要 7 分钟。
分布式锁一般有三种实现方式:
数据库乐观锁
基于ZooKeeper的分布式锁
基于Redis的分布式锁
这里主要记录下基于Redis的分布式锁
springboot2.1以后的版本可以直接使用redisTemplate提供的setIfAbsent方法进行加锁 相当于使用redis命令:SET key value [EX seconds] [PX millisecounds] [NX|XX]
redisTemplate.opsForValue().setIfAbsent(key,value,time,TimeUnit)
为什么是set命令而不是setNx命令?
因为setNx 无法设置key过期时间 需要通过expire来为key设置过期时间,意味着加锁是两条命令,不满足原子性。
锁的过期时间设置多少合适,是否可以不设置?
锁的过期时间一定是要有的,不然留着过年么?过期时间根据具体的业务逻辑来设置,但是一定要大于代码执行的时间。例如:
//加锁 锁的过期时间为5秒 Boolean lock = redisTemplate.opsForValue().setIfAbsent("111", "11", 5, TimeUnit.SECONDS); if(lock){ System.out.println("业务逻辑执行在0-8秒范围内"); }
这个时候肯定是不合适的。
加锁之后,一定要保证锁的释放,所以通常是在finally代码块里面释放锁。
获取到锁才释放锁,没有获取到,不要去释放锁,避免释放其他客户端加的锁。
释放锁的时候可以判断锁的持有者是否是自己,是自己的才进行释放。(2和3至少要遵循一个,这样才能避免误释放锁)
解锁方式一:
redisTemplate.delete(key)
解锁方式二:使用lua脚本
if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end
@Autowired RedisTemplate redisTemplate; @Test public void testLock() throws UnknownHostException { String key = "lockTest"; InetAddress ia = InetAddress.getLocalHost(); String value = ia.toString(); //加锁 锁的过期时间为20秒 Boolean lock = redisTemplate.opsForValue().setIfAbsent(key, value, 20, TimeUnit.SECONDS); if (!lock) { //未获取到锁,直接返回 return; } try { System.out.println("业务逻辑执行在小于20秒范围内"); } catch (Exception e) { System.out.println("业务错误信息"); } finally { // 方式一 直接使用del redisTemplate.delete(key); // 方式二 使用lua脚本 String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; RedisScript redisScript = new DefaultRedisScript(script); Listkeys = new ArrayList<>(); keys.add(key); redisTemplate.execute(redisScript, keys, value); } }
标题:JAVA 基于Redis的分布式锁
作者:hjljy地址:https://www.hjljy.cn/articles/2021/03/05/1614931478736.htmlEND
版权申明:内容来源网络,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知,我们会立即删除并表示歉意。谢谢。
如果你觉得文章不错,文末的赞 ???? 又回来啦,记得给我「点赞」和「在看」哦~
转载地址:http://hdaai.baihongyu.com/