前言
在项目中因为不小心把加锁和解锁的key写错了,导致线上故障,锁一直续约的问题。现在想想是否在代码设计层面能否杜绝掉这种因为粗心释放锁失败导致的线上问题产生
解决方案
实现思路:
1、加锁
2、在加锁的方法中同时向spring事务管理注册一个释放锁的钩子
3、事务提交或回滚后执行钩子释放分布式锁
代码如下:
public boolean tryLock(String lockName,int timeout) {
//是否有事务
? ? if(TransactionSynchronizationManager.isSynchronizationActive()) {
boolean isLock =false;
? ? ? ? RLock lock =null;
? ? ? ? String key =null;
? ? ? ? try{
key =LOCK_PREFIX + lockName;
? ? ? ? ? ? lock =redisson.getFairLock(key);
? ? ? ? ? ? //加锁
? ? ? ? ? ? isLock = lock.tryLock(timeout,TimeUnit.SECONDS);
? ? ? ? ? ? return isLock;
? ? ? ? }catch (InterruptedException ie){
//加锁失败中断线程
Thread.currentThread().interrupt();
? ? ? ? }finally {
//如果加锁成功,则向事务管理器注册释放锁的钩子
? ? ? ? ? ? if(isLock) {
//这里因为需要final变量传值,所以需要copy过去
? ? ? ? ? ? ? ? final String copyKey =key;
? ? ? ? ? ? ? ? final RLock copyLock = lock;
? ? ? ? ? ? ? ? TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
? ? ? ? ? ? ? ? ? ? public void afterCompletion(int status) {
//事务是否成功都需要释放锁
? ? ? ? ? ? ? ? ? ? ? ? copyLock.unlock();
? ? ? ? ? ? ? ? ? ? ? ? log.info("释放分布式锁成功key:{}", copyKey);
? ? ? ? ? ? ? ? ? ? }
});
? ? ? ? ? ? }
}
}
return false;
}
这就完成了加锁使用完毕后自动释放锁的功能,避免线上出现同样的释放锁失败的故障了,顺带还解决了加锁失败,线程自动中断的问题