使用redisson做redis分布式锁
redisson分布式锁
思路:使用spring的切面来切入需要加锁执行的操作或者方法,在调用方法前由切面捕获,然后通过方法的注解获取具体执行锁的参数,根据参数尝试取锁。持有锁以后执行方法,待方法执行完毕或持有锁时间超时时释放锁。
如果有异常根据情况释放锁或者执行后置操作。
锁:
/** * @author Zhang Qiang * @date 2019/10/28 10:04 */ @Data @AllArgsConstructor @Builder(toBuilder = true) public class RedisLock { private String key; private String value; }
## ReLock注解类
标明此注解为使用redis锁。通过切点获取需要使用锁的操作
/** * @author Zhang Qiang * @date 2019/10/28 11:49 */ @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface ReLock { /** * key */ String key() default ""; /** * 是否循环获取锁 * */ boolean isHold() default true; /** * 尝试加锁等待超时时间 */ long waitTime() default 300 * 1000L; /** * 最长持锁时间,到期自动解锁 */ long leaseTime() default 300 * 1000L; /** * 时间格式,默认ms */ TimeUnit timeUnit() default TimeUnit.MICROSECONDS; }
具体操作类:
/** * @author Zhang Qiang * @date 2019/10/28 14:11 */ @Slf4j @Component public class RedissonLockHandler { @Autowired private RedissonClient redissonClient; /** * 尝试加锁等待超时时间 */ private final static long LOCK_TRY_WAIT = 5 * 1000L; /** * 持锁时间,防止死锁 */ private final static long LOCK_EXPIRE = 10 * 1000L; public RLock getRLock(String key){ return redissonClient.getLock(key); } public boolean tryLock0(String key) { RLock rLock = redissonClient.getLock(key); return rLock.tryLock(); } public boolean tryLock(String key) throws InterruptedException{ return tryLock(key, LOCK_TRY_WAIT, LOCK_EXPIRE); } public boolean tryLock(String key, long waitTime, long leaseTime) throws InterruptedException { return tryLock(key, LOCK_TRY_WAIT, LOCK_EXPIRE, TimeUnit.MILLISECONDS); } /** * @param key 锁 * @param waitTime 等待时间 * @param leaseTime 持有锁时间 * @param unit 单位 * @return boolean */ public boolean tryLock(String key, long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException { RLock rLock = redissonClient.getLock(key); return rLock.tryLock(waitTime, leaseTime, unit); } public void unLock(String key) { RLock rLock = redissonClient.getLock(key); unLock(rLock); } public void unLock(RLock rLock){ if (rLock != null && rLock.isLocked()){ rLock.unlock(); } } }
实现切面:
/** * 定时任务 * 加锁执行 * @author Zhang Qiang * @date 2019/10/28 16:24 */ @Slf4j @Aspect @Order(0) @Component public class RedissonAspect { @Autowired RedissonLockHandler redissonLockHandler; @Pointcut("execution(public * com.qulv.vdn.product.service.impl.ProductTimedTaskServiceImpl.*(..))") public void redisRLockPointCut(){ } @Pointcut("execution(public * com.qulv.vdn.product.service.impl.SyncUserInfoByFailed.*(..))") public void redisRLockSyncUserInfoByFailedPointCut(){ } @Around("redisRLockPointCut() || redisRLockSyncUserInfoByFailedPointCut()") public Object timeTaskAround(ProceedingJoinPoint joinPoint){ Object rollBack = null; boolean isLocked = false; MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); Method method = methodSignature.getMethod(); if (method.isAnnotationPresent(ReLock.class)){ ReLock reLock = method.getAnnotation(ReLock.class); String key = reLock.key(); if ("".equals(key)) { key = getLockKey(methodSignature); } RLock rLock = redissonLockHandler.getRLock(key); if (rLock != null){ try { if (reLock.isHold()){ isLocked = redissonLockHandler.tryLock(key, reLock.waitTime(), reLock.leaseTime(), reLock.timeUnit()); } else { isLocked = redissonLockHandler.tryLock0(key); } if (isLocked){ log.info(" ===== 执行定时任务 ===== :{} ", method.getName() ); rollBack = joinPoint.proceed(); } else { log.warn("========== 获取锁失败,未执行 ============ : {} ", method.getName()); } } catch (Throwable throwable) { log.warn(" 获取 redisRLock 异常中断 : {}" , throwable.getMessage()); } finally { redissonLockHandler.unLock(rLock); } } } return rollBack; } private String getLockKey(MethodSignature methodSignature){ return methodSignature.getMethod().getName(); } }
posted on 2019-12-05 09:51 GhostSugar 阅读(1036) 评论(0) 编辑 收藏 举报