首页 > 数据库 >springboot封装redission的分布式锁逻辑为注解

springboot封装redission的分布式锁逻辑为注解

时间:2023-07-04 10:44:57浏览次数:42  
标签:事务 springboot distributedLock redission 切面 lock 注解 分布式

场景概述

使用分布式锁的时候,每次都需要使用try catch处理方法中的逻辑。考虑是否可以这块逻辑抽离出来。

实现

在自定义的注解中添加属性来设置锁的等待时间、租赁时间和时间单位

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DistributedLock {
    String value() default ""; // 锁的名称或标识符
    long waitTime() default 0; // 等待获取锁的时间
    long leaseTime() default -1; // 锁的租赁时间,-1表示无限期
    TimeUnit timeUnit() default TimeUnit.MILLISECONDS; // 时间单位
}

在切面类中获取注解的属性值,并将其传递给Redisson锁对象

@Aspect
@Component
@Order(1) // 设置切面的优先级,确保分布式锁注解在事务注解之前执行
public class DistributedLockAspect {

    private final RedissonClient redissonClient;

    @Autowired
    public DistributedLockAspect(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    @Around("@annotation(distributedLock)")
    public Object applyLock(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) throws Throwable {
        String lockName = distributedLock.value();
        RLock lock = redissonClient.getLock(lockName);
        long waitTime = distributedLock.waitTime();
        long leaseTime = distributedLock.leaseTime();
        TimeUnit timeUnit = distributedLock.timeUnit();

        boolean isLocked = false;
        try {
            isLocked = lock.tryLock(waitTime, leaseTime, timeUnit);
            if (isLocked) {
                return joinPoint.proceed();
            } else {
                throw new RuntimeException("Failed to acquire lock");
            }
        } finally {
            if (isLocked) {
                    // 是否是当前执行线程的锁
                    if(lock.isHeldByCurrentThread()){ 
                       // 释放锁
                        lock.unlock();
                    }
            }
        }
    }
}

在Spring Boot应用程序中启用AOP,并在需要加锁的方法上使用自定义的注解

@Service
public class MyService {

    @DistributedLock(value ="test" ,waitTime = 5, leaseTime = 10, timeUnit = TimeUnit.SECONDS)
    public void myMethod() {
        // 加锁后的业务逻辑
    }
}

在上述示例中,waitTime属性设置为5,表示等待锁的最长时间为5秒,leaseTime属性设置为10,表示锁的租赁时间为10秒,timeUnit属性设置为TimeUnit.SECONDS,表示时间单位为秒。

与事务注解一起使用会存在事务失效问题解决方案

在Spring中,注解和事务注解可以一起使用,但需要注意一些细节,以确保事务的正确运行。
默认情况下,Spring的事务管理器会在方法开始时创建一个事务,并在方法结束时提交或回滚事务。然而,如果在方法内部使用了自定义的注解,例如用于分布式锁的注解,事务管理器可能无法正确地处理这种情况,从而导致事务失效。
为了解决这个问题,可以通过调整切面的优先级来确保分布式锁注解在事务注解之前执行。通过设置较高的优先级,分布式锁注解的切面将在事务注解的切面之前执行,从而确保分布式锁的获取和释放在事务之外进行。
具体实现方式可以使用@Order注解或者实现Ordered接口来指定切面的执行顺序。例如,可以为分布式锁注解的切面设置一个较高的优先级,如@Order(1),而事务注解的切面设置一个较低的优先级,如@Order(2)
这样,分布式锁注解的切面会在事务注解的切面之前执行,确保分布式锁的获取和释放不会干扰事务的正常运行。
需要注意的是,使用分布式锁注解和事务注解一起时,要确保分布式锁的获取和释放的时间不会超过事务的执行时间,以避免锁的过期导致数据不一致的问题。可以根据实际情况调整锁的等待时间、租赁时间和时间单位,以确保锁的有效性和事务的一致性。

@Aspect
@Component
@Order(Ordered.HIGHEST_PRECEDENCE) // 设置切面的优先级为最高
public class DistributedLockAspect {

    private RedissonClient redissonClient;

    @Autowired
    public DistributedLockAspect(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    @Around("@annotation(distributedLock)")
    public Object applyLock(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) throws Throwable {
        RLock lock = redissonClient.getLock("lockName");
        long waitTime = distributedLock.waitTime();
        long leaseTime = distributedLock.leaseTime();
        TimeUnit timeUnit = distributedLock.timeUnit();

        boolean isLocked = false;
        try {
            isLocked = lock.tryLock(waitTime, leaseTime, timeUnit);
            if (isLocked) {
                return joinPoint.proceed();
            } else {
                throw new RuntimeException("Failed to acquire lock");
            }
        } finally {
            if (isLocked) {
                    // 是否是当前执行线程的锁
                    if(lock.isHeldByCurrentThread()){ 
                       // 释放锁
                        lock.unlock();
                    }
            }
        }
    }
}

在上述代码中,通过@Order(Ordered.HIGHEST_PRECEDENCE)设置了切面的优先级为最高,确保它在其他切面之前执行。

标签:事务,springboot,distributedLock,redission,切面,lock,注解,分布式
From: https://www.cnblogs.com/hello-czf/p/17525050.html

相关文章

  • SpringBoot教学资料6-SpringBoot登录注册功能实现(带简单前端)
     项目样式:      SQL:CREATETABLE`t_user`(`id`int(11)NOTNULLAUTO_INCREMENT,`username`varchar(32)NOTNULL,`password`varchar(32)NOTNULL,PRIMARYKEY(`id`),UNIQUEKEY`username`(`username`))ENGINE=InnoDBAUTO_INCR......
  • SpringBoot SpringCloud Nacos等一些组件版本对应
    毕业版本依赖关系(推荐使用)由于SpringBoot2.4+和以下版本之间变化较大,目前企业级客户老项目相关SpringBoot版本仍停留在SpringBoot2.4以下,为了同时满足存量用户和新用户不同需求,社区以SpringBoot2.4为分界线,同时维护2.2.x和2021.x两个分支迭代。2021.x分支......
  • SpringBoot教学资料5-SpringBoot一对多查询(带简单前端)
    项目展示:  项目结构:SQL:CREATETABLE`t_article`(`id`int(20)NOTNULLAUTO_INCREMENTCOMMENT'文章id',`title`varchar(200)DEFAULTNULLCOMMENT'文章标题',`content`longtextCOMMENT'文章内容',PRIMARYKEY(`id`))ENGINE=......
  • SpringBoot教学资料4-SpringBoot简单增删改查(带前端)
    最终样式:增: 删:  改:  项目结构:     - springboot1.5.9以下兼容jdk1.7- springboot2.x.x版本兼容jdk1.8- springboot3.0及以上版本兼容jdk17- springboot2.1之后的版本已经兼容JDK11 pom.xml:<?xmlversion="1.0"encoding="UTF-8"?><......
  • SpringBoot教学补充资料3-Maven安装
    Maven下载地址:https://maven.apache.org/download.cgi下载后进行解压,记住解压路径。         mvn -v ......
  • SpringBoot教学资料3-SpringBoot启动常见问题
    java.lang.RuntimeException:java.lang.RuntimeException:org.codehaus.plexus.component.repository.excMaven版本过高,与你使用的IDEA版本不兼容。推荐版本:maven3.6(建议)/maven3.9控制台Processterminatedhttps://blog.csdn.net/weixin_44589991/article/details/115013......
  • SpringBoot教学补充资料1-基础SQL语句
    #查询所有内容select*fromemployeeselect(属性1,属性2,...)from表名#通过id查询select*fromemployeewhereuid=1select(属性1,属性2,...)from表名where属性=指定的属性值#增加insertintoemployee(uid,uname,uage,uposition)values(8,'小黑',38,'实习生......
  • SpringBoot教学补充资料2-MyBatis简单查询项目
    SQL:CREATETABLE`tb_user`(`id`int(11)NOTNULLAUTO_INCREMENT,`username`varchar(20)DEFAULTNULL,`password`varchar(20)DEFAULTNULL,`gender`char(1)DEFAULTNULL,`addr`varchar(30)DEFAULTNULL,PRIMARYKEY(`id`))ENGINE=InnoDBA......
  • 分布式id---雪花算法
    为什么要用分布式id随着业务的增长,后期可能会对数据库进行拆分的操作,通过数据库中间间链接。如果数据库表中的id采取的是自增策略,则会产生重复的id。使用分布式id便是为了避免此类现象。雪花算法snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使......
  • 入选德勤粤港澳大湾区及广州高科技高成长两大榜单,巨杉数据库引领分布式数据库弯道超车
    巨杉数据库凭借在分布式数据库领域的优异表现和突出成果,入选2022德勤粤港澳大湾区高科技高成长40强及明日之星和广州高科技高成长20强及明日之星两大榜单。近日,经德勤中国与大湾区科技创新服务中心、广东粤港澳大湾区研究院联合组织征集、评选及审定,公布了2022德勤粤港澳大湾区高......