欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

如何利用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);    }

}
```