SpringBoot2.3.4整合Redisson实现分布式锁

概述

在分布式项目中经常需要用到分布式锁,直接使用redis相关命令SET key value [EX seconds] [PX milliseconds] [NX] [XX]或者命令SETNX可以实现分布式锁。
使用命令方式实现分布式锁存在一些问题,比如解锁之前发生程序异常,导致无法解锁,或者设置了过期时间,线程A获得的锁因过期被redis删除,而此时A还去执行DEL命令等问题,为了解决这些问题,还需要引入Lua脚本,这样就使程序更加复杂了,redis推出了更加方便实现分布式锁的组件Redisson,详情参看官方文档
基于Redis的Redisson分布式可重入锁RLock Java对象实现了java.util.concurrent.locks.Lock接口,使用方式跟ReentrantLock一样。
本文主要介绍SpringBoot2.3整合Redisson实现分布式锁的简单实现,为了方便测试,使用了swagger作为测试工具

引入依赖

SpringBoot整合Redisson核心依赖如下:

<dependency>
    <groupId>org.redissongroupId>
    <artifactId>redisson-spring-boot-starterartifactId>
    <version>3.13.5version>
dependency>
<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-data-redisartifactId>
dependency>

配置文件

Redisson有两种配置方式,程序化配置和yml文件配置
程序化配置方法是通过构建Config对象实例来实现,代码如下:

@Bean(destroyMethod = "shutdown")
public RedissonClient redisson() throws IOException {
     
    Config config = new Config();
    config.useSingleServer().setAddress("redis://192.168.108.11:6379");
    return Redisson.create(config);
}

Redisson支持多种模式,比如集群模式、哨兵模式、主从模式等,本文才有单节点模式
yml文件配置需要新建一个yml文件单独配置Redisson相关属性,不能配置在application.yml配置文件中,主要的配置如下:

singleServerConfig:
  idleConnectionTimeout: 10000 #连接空闲超时(毫秒),默认10000
  connectTimeout: 10000 #连接空闲超时(毫秒),默认10000
  timeout: 3000 #命令等待超时(毫秒),默认3000
  retryAttempts: 3 #命令失败重试次数
  retryInterval: 1500 #命令重试发送时间间隔(毫秒),默认1500
  password: null
  subscriptionsPerConnection: 5 #单个连接最大订阅数量,默认5
  clientName: null #客户端名称
  address: "redis://127.0.0.1:6379"
  subscriptionConnectionMinimumIdleSize: 1 #发布和订阅连接的最小空闲连接数,默认1
  subscriptionConnectionPoolSize: 50 #发布和订阅连接池大小,默认50
  connectionMinimumIdleSize: 24 #最小空闲连接数,默认32
  connectionPoolSize: 64 #连接池大小,默认64
  database: 0
  dnsMonitoringInterval: 5000 #DNS监测时间间隔(毫秒),默认5000
threads: 16
nettyThreads: 32
codec: ! {
     }
"transportMode": "NIO"

此处需要注意的是Redisson中文网提供的示例在项目启动的时候会报错,使用英文网提供的示例是可以正常启动项目的,估计是中文网的文档没有及时更新,以上配置摘自Redisson英文网
使用yml文件配置还需要新建一个配置类加载配置文件,实例化RedissonClient,代码如下:

@Bean(destroyMethod = "shutdown")
public RedissonClient redisson() throws IOException {
     
    Config config = Config.fromYAML(new ClassPathResource("application-single.yml").getInputStream());
    RedissonClient redisson = Redisson.create(config);
    return redisson;
}

注意:用ClassPathResource方式加载配置文件

实现分布式锁核心代码

public AjaxResult selectUserForLockById(@PathVariable Long id) {
     
    String key = "user_" + id;
    RLock readLock = redissonService.getReadLock(key);
    readLock.lock();//加锁
    //readLock.lock(10, TimeUnit.SECONDS);可以设置锁的过期时间,如果不设置redisson默认30秒
    SysUser user = new SysUser();
    try {
     
        logger.info("加锁成功,开始执行查询业务...");
        user = userService.getById(id);
    } catch (Exception e) {
     
        e.printStackTrace();
    } finally {
     
        logger.info("释放锁....");
        readLock.unlock();
    }
    return AjaxResult.ok().data("user", user);
}

信号量核心代码

public AjaxResult selectUserForSemaphoreById(@PathVariable Long id) {
     
    String key = "user_semaphore_" + id;
    RSemaphore semaphore = redissonService.getSemaphore(key);
    //设置初始信号量数量
    semaphore.trySetPermits(5);
    SysUser user = new SysUser();
    try {
     
        boolean flag = semaphore.tryAcquire();
        if (flag) {
     
            logger.info("获取信号量成功,开始执行任务......");
            user = userService.getById(id);
            logger.info("业务执行完成,释放信号量......");
            semaphore.release();
        } else {
     
            logger.info("获取信号量失败,直接返回消息......");
            user = null;
        }
    } catch (Exception e) {
     
        e.printStackTrace();
    }
    return AjaxResult.ok().data("user", user);
}

Redisson还提供了公平锁、联锁、红锁、闭锁等实现,本文不做一一介绍了,更多详情参看Redisson官网

你可能感兴趣的:(SpringBoot,spring,boot,redis,缓存,分布式)