东营网站制作公司,中山企业网站建设公司,优化防控举措,展会电子商务网站如何建设前言 首先#xff0c;为了确保分布式锁可用#xff0c;我们至少要确保锁的实现同时满足以下四个条件#xff1a; 互斥性。在任意时刻#xff0c;只有一个客户端能持有锁。不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁#xff0c;也能保证后续其他客户…前言 首先为了确保分布式锁可用我们至少要确保锁的实现同时满足以下四个条件 互斥性。在任意时刻只有一个客户端能持有锁。不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁也能保证后续其他客户端能加锁。具有容错性。只要大部分的Redis节点正常运行客户端就可以加锁和解锁。加锁和解锁必须是同一个客户端客户端自己不能把别人加的锁给解了。 实现
首先引入jedis组件依赖pom中添加如下配置 dependencygroupIdredis.clients/groupIdartifactIdjedis/artifactId/dependency加锁代码 private static final String LOCK_SUCCESS OK;/*** 该加锁方法仅针对单实例 Redis 可实现分布式加锁* 对于 Redis 集群则无法使用* 支持重复线程安全** param lockKey 加锁键* param requestId 加锁客户端唯一标识* param milliseconds 锁过期时间:此处使用的单位为 px-毫秒数若需要单位为秒则改用parms.ex(int seconds)* return*/public Boolean tryLock(String lockKey, String requestId, long milliseconds) {SetParams parms new SetParams();parms.px(milliseconds);return redisTemplate.execute((RedisCallbackBoolean) redisConnection - {Jedis jedis (Jedis) redisConnection.getNativeConnection();String result jedis.set(lockKey, requestId, parms);return LOCK_SUCCESS.equals(result);});}第一个参数加锁的key当前没有锁key不存在那么就进行加锁操作已有锁存在不做任何操作。 第二个参数为确保安全性需要key和value都一致才会解锁。 第二个参数(看代码注释) 解锁代码
private static final Long RELEASE_SUCCESS 1L;// if get(key) value return del(key)private static final String RELEASE_LOCK_SCRIPT if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end;/*** 与 tryLock 相对应用作释放锁** param lockKey 加锁键* param requestId 加锁客户端唯一标识* return*/public Boolean releaseLock(String lockKey, String requestId) {return redisTemplate.execute((RedisCallbackBoolean) redisConnection - {Jedis jedis (Jedis) redisConnection.getNativeConnection();Object result jedis.eval(RELEASE_LOCK_SCRIPT, Collections.singletonList(lockKey),Collections.singletonList(requestId));return RELEASE_SUCCESS.equals(result);});}解锁的思路是使用eval()提交一个Lua脚本代码首先获取锁对应的value值检查是否与requestId相等如果相等则删除锁解锁。 那为什么使用eval()在eval命令执行Lua代码的时候Lua代码将被当成一个命令去执行直到eval命令执行完成Redis才会执行其他命令。也就是说这个操作满足原子性保证了安全性。