redis 分布式锁注意事项
- 1.互斥性:在任意时刻,只有一个客户端持有锁
- 2.一致性:加锁和解锁必须在同一个客户端,而且客户端自己不能把别人的锁解了;
- 3.避免死锁:即使有一个客户端在持有锁期间崩溃了而没有主动解锁,也能保证后续其他客户端能加锁
参考代码实现
if(redisTemplate.opsForValue().setIfAbsent("getsnInfo","11")){ //key的值放什么不重要,重要的是key.所以11或者aa都行。多个定时任务,是多个key,不能set一样的,各管各的定时任务。懂redis的应该都明白 try{ // 业务代码 }catch(){ redisTemplate.delete("getsnInfo"); } redisTemplate.delete("getsnInfo"); }
问题分析:
上述代码满足分布式锁的互斥性;
没有避免死锁,假如加锁的客户端挂掉,锁将一直存在,需要给加的锁添加过期时间;
如果保证一致性呢,删除的时候 判断 取出来的值 是否 放进去的值;
代码优化:
/** * 使用redis的set命令实现获取分布式锁 * @param lockKey 可以就是锁 * @param requestId 请求ID,保证同一性 * @param expireTime 过期时间,避免死锁 秒 * @return */ public boolean getLock(String lockKey,String requestId,int expireTime) { Jedis jedis = null; try { jedis = jedisPool.getResource() ; //NX:保证互斥性 String result = jedis.set(lockKey, requestId, "NX", "EX", expireTime); if("OK".equals(result)) { return true; } return false; } catch (Exception e) { e.printStackTrace(); return false; }finally { release(jedis); } }
/** * 释放分布式锁 * @param lockKey * @param requestId */ public boolean releaseLock(String lockKey,String requestId) { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; Jedis jedis = null; try { jedis = jedisPool.getResource(); Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId)); if (result.equals(1L)) { return true; } return false; } catch (Exception e) { e.printStackTrace(); return false; } finally { release(jedis); } }
什么是分布式锁? 为啥需要分布式锁?
分布式锁 是分布式架构下 同步访问共享资源的一种方式