栏目分类:
子分类:
返回
终身学习网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
终身学习网 > IT > 软件开发 > 后端开发 > Java

四、Redisson分布式锁的实现

Java 更新时间:发布时间: 百科书网 趣学号
一、示例一:使用AOP实现Redis分布式锁

详情参考:Redisson分布式锁使用说明
1、在需要添加同步控制的业务对象中,首先引入redissonClient;
2、在具体业务方法上创建锁对象 redissonClient.getLock;
(getLock中的参数是自己根据业务拼接的字符串,整个系统中如果遇到相同字符串的锁定变量信息,将同步处理)
3、对同步块采用封装处理;

注:getLock与tryLock区别:
RLock lock=redissonClient.getLock():创建锁对象;
lock.tryLock():尝试获取锁;

public class TestReentrantLock {
    @Autowired
    private RedissonClient redissonClient;
    RLock lock = redissonClient.getLock(${锁定变量}); 
    try{
        if (lock.tryLock(10, TimeUnit.SECONDS)) {//尝试获取锁,如果超过10秒,进入异常流程
            try {
                //获得锁,进行业务处理(处理过程中同样的SceneType.VALIDATE_MOBILE.name()+uuid 值在全局内不能再次进入,保证同步性)
                //业务代码块 
            } catch (Exception e) {
                //业务报错异常处理分支

            } finally {
                lock.unlock();// 释放锁
            }
        } else {
            //获取锁超时处理分支
            //可以返回可控的处理信息 例如:"系统繁忙,请过后尝试!"
        }
    } catch(InterruptedException e){
        // trylock 线程阻塞Interrupt
        // 静默处理!
    }
}
二、示例二:使用AOP实现Redis分布式锁

第一步:自定义切面类:

@Component
@Aspect
@Slf4j
public class RedisLockAspect {
    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private RedisProperties redisProperties;

    @Around("@annotation(com.asd.core.annotation.RedisLock)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
        Method proxyMethod = ((MethodSignature)joinPoint.getSignature()).getMethod();
        Method realMethod = joinPoint.getTarget().getClass().getDeclaredMethod(proxyMethod.getName(), proxyMethod.getParameterTypes());
        RedisLock redisLock = realMethod.getAnnotation(RedisLock.class);
        if (joinPoint.getArgs().length>0&&joinPoint.getArgs()[0] instanceof UserDTO){
            String certNo=((UserDTO)joinPoint.getArgs()[0]).getCertNo();
            //Redis分布式锁,同一用户同一时间只能单一查询
            RLock lock=null;
            try{
                lock = redissonClient.getLock(redisLock.prefix()+realMethod.getName()+":"+certNo);
                log.debug("lock:{}",lock.getName());

                if (!lock.tryLock(-1, redisProperties.getLockExpireInSeconds(), TimeUnit.SECONDS)){
                    throw new SametimeQueryException();
                }
            }catch (RedisException e){
                log.error("Redis异常,加锁失败",e);
            }
            try {
                return joinPoint.proceed();
            }finally {
                try{
                    if (lock!=null){
                        lock.unlock();
                    }
                }catch (RedisException e){
                    log.error("Redis异常,解锁失败",e);
                }
            }
        }

        //一般不会走到这步,除非方法参数异常
        throw new UnknownException();
    }
}

第二步:自定义切面注解:

@Inherited
@documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisLock {
    String prefix() default "shop:Lock:";
    long waitSecond() default -1;
    long expireTime() default 10;
    TimeUnit unit() default TimeUnit.SECONDS;
}

第三步:业务类中使用切面注解:
查询时:同一用户同一时间只能单一查询;

public class QueryServiceImpl implements QueryService{
    @RedisLock
    @Override
    public User queryUser(String name){
        ...
    }
}

注意一: tryLock()方法介绍::

详细参考一:Lock的tryLock()方法
详细参考二:redisson锁 tryLock的使用及正确用法

tryLock()方法是有返回值的,它表示用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false,这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待;具有三种构造方法:①无参;②包含 失效时间、单位 两个参数的构造方法;③包含 等待时间,失效时间,单位三个参数的构造方法; 示例二的自定义切面类中用的是第三种。

public class TestReentrantLock {
    public void testReentrantLock(RedissonClient redisson){
        RLock lock = redisson.getLock("anyLock");
        try{
            //1.无参 (最常见的使用方法)
            //lock.lock();
            
            //2.两个参数:失效时间,单位 (支持过期解锁功能,10秒钟以后自动解锁, 无需调用unlock方法手动解锁)
            //lock.lock(10, TimeUnit.SECONDS);
            
            //3.三个参数:等待时间,失效时间,单位 (尝试加锁,最多等待3秒,上锁以后10秒自动解锁)
            boolean res = lock.tryLock(3, 10, TimeUnit.SECONDS);
            if(res){ //成功
                // do your business
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

注意二:1. RedisProperties.java:

@Component
@Data
@ConfigurationProperties("asd.core.redis")
public class RedisProperties {
    private Integer lockExpireInSeconds;
    private Integer rateLimiterTimeout;
}

2. application.yml:

pboc:
  core:
    redis:
      lock-expire-in-seconds: 30
      rate-limiter-timeout: 10

3. 对于@ConfigurationProperties(“asd.core.redis”)的使用:

详细参考:@ConfigurationProperties注解的基本使用

在SpringBoot使用@ConfigurationProperties注解读取yml/properties配置文件参数:在配置文件中所配置的参数都正确的注入到Java类对象中,而类中存在,但配置文件中没有配置的属性值默认为null。

转载请注明:文章转载自 www.051e.com
本文地址:http://www.051e.com/it/270319.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 ©2023-2025 051e.com

ICP备案号:京ICP备12030808号