springboot-note
springboot-note copied to clipboard
redis加错未采用原子操作
boolean isSuccess = redisTemplate.opsForValue().setIfAbsent(businessKey, uniqueValue);
if (!isSuccess) {
throw new Exception("You can't do it,because another has get the lock =-=");
}
redisTemplate.expire(businessKey, annotation.lockTime(), TimeUnit.SECONDS);
这块redis操作,不是原子的,如果在设置过期时间前,突然宕机了,则加锁后的key将长时间存在, 应该用 Boolean setIfAbsent(K key, V value, long timeout, TimeUnit unit);
已接纳你的建议,在代码中修复 Issue 1 & 2 的问题
定时线程这一块感觉还有点问题, 当一个线程获锁之后执行完毕后另一个线程立即获锁,这个时候延时队列里面可能会存在两条数据一直在重试,当新的线程执行完毕后去释放锁
RedisLockDefinitionHolder redisLockDefinitionHolder = holderList.stream().filter(h -> businessKey.equals(h.getBusinessKey())).findFirst().orElse(null);
if (redisLockDefinitionHolder != null && redisLockDefinitionHolder.getCurrentTread().equals(currentThread)) {
// 请求结束后,强制删掉 key,释放锁
redisTemplate.delete(businessKey);
log.info("release the lock, businessKey is [" + businessKey + "]");
}
上面这段逻辑可能会导致锁无法释放掉 建议释放锁的时候顺便将队列里面的该条数据删除
定时线程这一块感觉还有点问题, 当一个线程获锁之后执行完毕后另一个线程立即获锁,这个时候延时队列里面可能会存在两条数据一直在重试,当新的线程执行完毕后去释放锁
RedisLockDefinitionHolder redisLockDefinitionHolder = holderList.stream().filter(h -> businessKey.equals(h.getBusinessKey())).findFirst().orElse(null); if (redisLockDefinitionHolder != null && redisLockDefinitionHolder.getCurrentTread().equals(currentThread)) { // 请求结束后,强制删掉 key,释放锁 redisTemplate.delete(businessKey); log.info("release the lock, businessKey is [" + businessKey + "]"); }
上面这段逻辑可能会导致锁无法释放掉 建议释放锁的时候顺便将队列里面的该条数据删除
是个很好的建议,已添加到代码中:commit log