如何利用Redisson实现Redis的分布式锁定功能
最编程
2024-07-28 19:25:18
...
***备份用***
~使用redisson做redis分布式锁
redisson分布式锁思路:使用spring的切面来切入需要加锁执行的操作或者方法,在调用方法前由切面捕获,然后通过方法的注解获取具体执行锁的参数,根据参数尝试取锁。持有锁以后执行方法,待方法执行完毕或持有锁时间超时时释放锁。如果有异常根据情况释放锁或者执行后置操作。
## pom
```
<properties> <java.version>1.8</java.version> <spring-boot.version>2.1.6.RELEASE</spring-boot.version> <dubbo.version>2.7.1</dubbo.version> <nacos-client.version>1.0.0</nacos-client.version> <protobuf.version>3.6.1</protobuf.version> <grpc.version>1.6.1</grpc.version> <rocket.version>2.0.3</rocket.version> <redisson.version>3.11.2</redisson.version> <aliyun.oss.version>3.4.2</aliyun.oss.version> <aop.version>2.1.6</aop.version> </properties>
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>${redisson.version}</version> </dependency> <dependency> <groupId>com.qulv</groupId> <artifactId>vdn.api</artifactId> <version>1.0-SNAPSHOT</version> <scope>compile</scope> </dependency> <dependency> <groupId>com.qulv</groupId> <artifactId>vdn.common</artifactId> <version>1.0-SNAPSHOT</version> <scope>compile</scope> </dependency> </dependencies>```
## RedisLock 锁```package com.qulv.vdn.cache.model;
import lombok.AllArgsConstructor;import lombok.Builder;import lombok.Data;
/** * @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;
}
```
## RedisTaskLockHandler操作类,具体操作具体执行,和下面的Redission同样
```javapackage com.qulv.vdn.cache;
import com.qulv.vdn.cache.model.RedisLock;import lombok.extern.slf4j.Slf4j;import org.redisson.Redisson;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.RedisCallback;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.ValueOperations;import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/** * @author Zhang Qiang * @date 2019/10/28 9:57 */@Slf4j@Componentpublic class RedisTaskLockHandler {
@Autowired RedisClient redisClient;
@Autowired RedisTemplate redisTemplate;
/** * 是否循环获取锁 */ private final static boolean IS_CYCLE = true;
/** * 默认尝试间隔 1000ms */ private final static long LOCK_TRY_INTERVAL = 1000L;
/** * 默认尝试超时时间 10s */ private final static long LOCK_TRY_TIMEOUT = 10 * 1000L;
/** * 单个业务持有锁的时间,防止死锁 30s */ private final static long LOCK_EXPIRE = 30 * 1000L;
/** * 尝试获取全局锁 * * @return */ public boolean tryLock(RedisLock redisLock){ return getLock(redisLock, LOCK_TRY_TIMEOUT, LOCK_TRY_INTERVAL, LOCK_EXPIRE, IS_CYCLE); } public boolean tryLock(RedisLock redisLock, long timeOut){ return getLock(redisLock, timeOut, LOCK_TRY_INTERVAL, LOCK_EXPIRE, IS_CYCLE); } public boolean tryLock(RedisLock redisLock, long timeOut, long tryInterval){ return getLock(redisLock, timeOut, tryInterval, LOCK_EXPIRE, IS_CYCLE); } public boolean tryLock(RedisLock redisLock, boolean is_cycle){ return getLock(redisLock, LOCK_TRY_TIMEOUT, LOCK_TRY_INTERVAL, LOCK_EXPIRE, is_cycle); } public boolean tryLock(RedisLock redisLock, long timeOut, boolean is_cycle){ return getLock(redisLock, timeOut, LOCK_TRY_INTERVAL, LOCK_EXPIRE, is_cycle); } public boolean tryLock(RedisLock redisLock, long timeOut, long tryInterval, boolean is_cycle){ return getLock(redisLock, timeOut, tryInterval, LOCK_EXPIRE, is_cycle); } public boolean tryLock(RedisLock redisLock, long timeOut, long tryInterval, long lockExpireTime, boolean isCycle){ return getLock(redisLock, timeOut, tryInterval, lockExpireTime, isCycle); }
/** * 获取锁/写入锁 * * @param redisLock 锁 * @param timeOut 超时时间 ms * @param tryInterval 尝试间隔 ms * @param lockExpireTime 锁过期时间 * @return boolean */ public boolean getLock( RedisLock redisLock, long timeOut, long tryInterval, long lockExpireTime, boolean isCycle){ String key = redisLock.getKey(); try { if ( key != null && key.length() != 0){ if (isCycle){ long startTime = System.currentTimeMillis(); while (redisTemplate.hasKey(key)){ log.warn(" redisLock : {} is exist", key); if ((System.currentTimeMillis() - startTime) > timeOut) { log.warn(" 获取 redisLock 超时 "); return false; } Thread.sleep(tryInterval); } } if (!redisTemplate.hasKey(key)){ setRedisLock(redisLock, lockExpireTime); return true; } else { log.warn(" redisLock : {} is exist", key); return false; } } else { throw new IllegalStateException(" redisLock key 不能为空!"); } } catch (InterruptedException e) { log.error(" 获取 redisLock 线程等待中断, {} ", e.getMessage()); return false; } }
/** * 设置值 * * @param redisLock * @param lockExpireTime * @return */ private void setRedisLock(RedisLock redisLock, long lockExpireTime ){ ValueOperations operations = redisTemplate.opsForValue(); operations.set(redisLock.getKey(), redisLock.getValue(), lockExpireTime, TimeUnit.MILLISECONDS); }
/** * 释放锁 * * @param lock * @param value * @return */ public void releaseLock(RedisLock lock, String value) { this.releaseLock(lock.getKey(), value); } public void releaseLock(String key, String value) { if (key == null && key.length() == 0) { log.info(" There is no lock : {} ", key); } else { ValueOperations operations = redisTemplate.opsForValue(); String v = (String) operations.get(key); if (!v.equals(value)){ throw new IllegalStateException(" === 非正常释放锁 === "); } else { redisTemplate.delete(key); } } }
}
```
## RedissonLockHandler
```package com.qulv.vdn.cache;
import lombok.extern.slf4j.Slf4j;import org.redisson.api.RLock;import org.redisson.api.RedissonClient;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/** * @author Zhang Qiang * @date 2019/10/28 14:11 */@Slf4j@Componentpublic 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(); } }
}
```
## 切面类
```/** * 同步推送 * 注解@SyncProductUser(syncHandle = SyncProductHandleEnum.REG_USER_PAY_RECORD, syncType = PayRecord.class, tags = MQTags.PRODUCT_USER_ADD_PAY_RECORD) * @author Zhang Qiang * @date 2019/11/27 9:21 */@Slf4j@Component@Aspectpublic class SyncUserAspect {
@Autowired private SyncMethod syncMethod; @Reference(version = "${product.service.version}") private CompanyService companyService;
@Pointcut("execution(public * com.qulv.vdn.product.controller.User*Controller.*(..))") public void controllerSyncUserCut(){}
@Pointcut("execution(public * com.qulv.vdn.product.controller.UserHandlerController.productUserAdd(..))") public void userHandlerControllerAddUser(){}
@Around("userHandlerControllerAddUser()") public Object syncUserControllerAround(ProceedingJoinPoint point){ Result result = null; MethodSignature methodSignature = (MethodSignature) point.getSignature(); Method method = methodSignature.getMethod(); try { result = (Result) point.proceed(); } catch (Throwable throwable) { log.error("【方法执行异常】 msg :{}", throwable.getMessage()); throwable.printStackTrace(); throw new BusinessException(ResultCode.RESULT_ADVICE_EXCEPTION, throwable.getMessage()); } if (method.isAnnotationPresent(SyncProductUser.class)) { SyncProductUser syncProductUser = method.getAnnotation(SyncProductUser.class); if (result.getCode().equals(ResultCode.RESULT_SUCCESS.getType())) { analysisExecute(syncProductUser, result); } } return result; }
/** * 执行 * @param syncProductUser * @param result * @return */ private void analysisExecute(SyncProductUser syncProductUser, Result result){ try { Class clazz = syncProductUser.syncType(); log.info("【推送操作】:{}", syncProductUser.syncHandle());
if (syncProductUser.syncHandle() == SyncProductHandleEnum.SYNC_USER && syncProductUser.syncType() == User.class){
User user = (User) result.getData(); this.syncUser(user, syncProductUser.tags().getTag());
} else if (syncProductUser.syncHandle() == SyncProductHandleEnum.REG_USER_PAY_RECORD && clazz == PayRecord.class){ JSONObject jsonObject = (JSONObject) result.getData(); User user = (User) jsonObject.get("productUser"); PayRecord payRecord = (PayRecord) jsonObject.get("payRecord"); this.syncUser(user, syncProductUser.tags().getTag()); this.syncPayRecord(payRecord, syncProductUser.tags().getTag()); } } catch (ClassCastException | NullPointerException e){ log.error( "【空指针或结果转换异常】 msg :{}", e.getMessage()); throw e; } }
/** * 推送用户信息 * @param user * @param tags * @return */ private void syncUser(User user, String tags) { log.info("=========同步用户推送========= tags:{}", tags); ProductUser productUser = new ProductUser(); BeanUtils.copyProperties(user, productUser); productUser.setCompanyName(user.getRealName()); syncMethod.syncProductUser(productUser, tags); }
/** * 推送注册新增订单 * @param payRecord * @param tags * @return */ private void syncPayRecord(PayRecord payRecord, String tags){ log.info("=========注册订单推送==========="); syncMethod.syncProductRegPayRecord(payRecord, tags); }
}
```
上一篇: FileChannel
推荐阅读
-
使用 Redis 的分布式锁定原理、实现和优化
-
使用 Redis setNX 实现分布式锁 (包括重复数据插入的排他锁定)
-
详解Redis与Redisson的lock和tryLock功能实现机制
-
如何利用Redisson实现Redis的分布式锁定功能
-
使用 Redisson 实现的 redis 分布式锁在 SpringBoot 中的简单使用
-
如何用Redisson实现实时的分布式锁定机制
-
如何用Redisson实现分布式锁定机制(第二部分):RedissonLock详解
-
如何在SpringBoot中使用Redisson实现实时分布式锁的简单教程示例
-
在Redis中,如何使用RedissonLock来实现锁的等待功能?
-
如何在Redisson中实现轻松的获取与释放锁功能