关闭

Springboot 集成 redisson 实现分布式锁

古今自逍遥 1年前 ⋅ 607 阅读

一、介绍Redisson

Redisson是Redis官方推荐的Java版的Redis客户端(Jedis、letture也是官方推荐的java版本redis客户端程序)。它提供的功能非常多,也非常强大,特别是它默认提供的分布式锁支持功能。其github源码仓库地址:GitHub - redisson/redisson: Redisson - Redis Java client with features of In-Memory Data Grid. Over 50 Redis based Java objects and services: Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Publish / Subscribe, Bloom filter, Spring Cache, Tomcat, Scheduler, JCache API, Hibernate, MyBatis, RPC, local cache ...,包含多个子项目,对于我们本节比较有用的是

  • 集成redisson-spring-data-2x之后能够支持Spring Data redis及RedisTemplate
  • 集成redisson-spring-boot-starter能够支持Spring Cache(前提是已经集成spring-boot-starter-cache)

也就是说我们可以使用redisson无缝、无损的替换Spring Boot 2.x官方默认支持的redis客户端letture。也就是说我们之前学过的RedisTemplate、Redis Repository、Cache缓存该怎么用还怎么用,不受影响。

但是需要说明的是Redisson并不在Spring Boot官方默认支持的redis客户端的范围之内,所以redisson向Spring Boot 或者 Spring Data的集成方案,都是由redisson自己来维护的。

二、Spring Boot 集成Redisson

先从IDEA-maven管理Tab中查看,要确保自己的项目里面已经引入了下图所示的spring-boot-starter-data-redis。

如上所示,我们使用的是spring data 2.2.4版本,所以artifactId为redisson-spring-data-22。如果你使用的其他的版本,以此类推。

<dependency>
     <groupId>org.redisson</groupId>
     <!-- for Spring Data Redis v.2.2.x -->
     <artifactId>redisson-spring-data-22</artifactId>
     <version>3.15.0</version>
 </dependency>

除此之外,还要加入核心jar包redisson-spring-boot-starter,我们使用的是3.15.0版本,其默认包含redisson-spring-data-23,和我们Spring Data Redis v.2.2.x不匹配,所以我们用exclusion把它排除掉。

<dependency>
  <groupId>org.redisson</groupId>
  <artifactId>redisson-spring-boot-starter</artifactId>
  <version>3.15.0</version>
  <exclusions>
    <exclusion>
      <groupId>org.redisson</groupId>
      <!-- 默认是 Spring Data Redis v.2.3.x ,所以排除掉-->
      <artifactId>redisson-spring-data-23</artifactId>
    </exclusion>
  </exclusions>
</dependency>

下面的这一步从我的实验来看,可做可不做,不影响。但是既然我们使用redisson替换lettuce,就不要把lettuce的jar留在项目里面了,把它也排除掉。

三、两种配置方法

3.1.配置方法一

redisson-spring-boot-starter默认支持application全局配置文件,redis配置以前怎么配置,现在还怎么配置,把lettuce段的配置去掉就可以了。

3.2.配置方法二

首先把全局配置文件中spring.redis下面的配置全都删除掉,然后加上redisson独立配置文件的指向位置及文件名称

spring:
  redis:
    redisson:
      file: classpath:redisson.yaml

在resource目录下新建一个文件redisson.yaml,比如:redis单例模式的配置方法如下:

哨兵模式、集群模式等更多配置参考:https://github.com/redisson/redisson/wiki/目录

singleServerConfig:
  idleConnectionTimeout: 10000
  connectTimeout: 10000
  timeout: 3000
  retryAttempts: 3
  retryInterval: 1500
  password: 123456
  subscriptionsPerConnection: 5
  clientName: null
  address: "redis://192.168.161.3:6379"
  subscriptionConnectionMinimumIdleSize: 1
  subscriptionConnectionPoolSize: 50
  connectionMinimumIdleSize: 32
  connectionPoolSize: 64
  database: 0
  dnsMonitoringInterval: 5000
threads: 0
nettyThreads: 0
codec: !<org.redisson.codec.JsonJacksonCodec> {}
transportMode: "NIO"

大家可以看到第二种配置方案比第一种配置方案,多出很多细节方面的配置,更适合有经验的高手进行性能优化使用。

四、分布式锁的实现

仍然是老套路,获取锁、上锁锁定、业务代码执行完成释放锁。

@Resource
private RedissonClient redissonClient;
 
public void updateUser(String userId) {
  String lockKey = "config" + userId;
  RLock lock = redissonClient.getLock(lockKey);  //获取锁资源
  try {
    lock.lock(10, TimeUnit.SECONDS);   //加锁,可以指定锁定时间
 
    //这里写需要处理业务的业务代码
  } finally {
    lock.unlock();   //释放锁
  }
}
@Resource
private RedissonClient redissonClient;
 
public void updateUser(String userId) {
  String lockKey = "config" + userId;
  RLock lock = redissonClient.getLock(lockKey);  //获取锁资源
  try {
    //加锁,10秒钟,加锁20秒后自动解锁
    boolean lock = lock.tryLock(10,20, TimeUnit.SECONDS);   
    if (lock) {
        //这里写需要处理业务的业务代码
     }
  
  } finally {
    //判断锁是否处于锁定并且是当前线程锁定
    if (lock.isLocked() && lock.isHeldByCurrentThread()) {
       lock.unlock();//释放锁
    }
  }
}
  • 相对于RedisLockRegistry另一个小优点是:我们可以为每一个锁指定锁定的超时时间。RedisLockRegistry目前只能针对所有的锁设定统一的超时时间
  • 如果业务执行超时之后,再去unlock会抛出java.lang.IllegalMonitorStateException

全部评论: 0

    我有话说: