[springboot专栏]RedisLockRegistry实现分布式锁

在这里插入图片描述

一、集成spring-integration-redis

前提项目里面已经正确的集成了spring-boot-starter-data-redis,参考本专栏前面文章《单例、哨兵、集群模式整合》

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<dependency>
     <groupId>org.springframework.integration</groupId>
     <artifactId>spring-integration-redis</artifactId>
</dependency>

二、注册RedisLockRegistry

完成RedisLockRegistry Bean注册

@Configuration
public class RedisLockConfig {
    
    

     @Bean
     public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory) {
    
    
         //第一个参数redisConnectionFactory
         //第二个参数registryKey,分布式锁前缀,设置为项目名称会好些
         //该构造方法对应的分布式锁,默认有效期是60秒.可以自定义
         return new RedisLockRegistry(redisConnectionFactory, "boot-launch");
         //return new RedisLockRegistry(redisConnectionFactory, "boot-launch",60);
     }
}

三、使用RedisLockRegistry

使用RedisLockRegistry完成获取锁、加锁以及完成业务之后的释放锁的操作。

@Resource
private RedisLockRegistry redisLockRegistry;

public void updateUser(String userId) {
    
    
  String lockKey = "config" + userId;
  Lock lock = redisLockRegistry.obtain(lockKey);  //获取锁资源
  try {
    
    
    lock.lock();   //加锁
        
    //这里写需要处理业务的业务代码
  } finally {
    
    
    lock.unlock();   //释放锁
  }
}

四、RedisLockRegistry解读

org.springframework.integration.redis.util.RedisLockRegistry的核心源码非常简单,就RedisLockRegistry这一个类。源码我就不贴在这里了,我给大家总结一下要点:

  • 基于StringRedisTemplate实现,所以与spring-boot-starter-data-redis天然融合。
  • RedisLockRegistry可以结合Spring data redis实现分布式锁,registryKey是锁key的前缀。
  • 默认的锁过期时间是60秒,提供了自定义RedisLockRegistry(redisConnectionFactory, registryKey,expiredAfter)的构造函数可以使用
  • 当尝试去unlock已经过期的锁的时候,会抛出异常IllegalStateException,即RedisLockRegistry不支持锁的续期
  • RedisLockRegistry实现的分布式锁是“可重入”的,可重入就是说某个线程已经获得某个锁,该线程可以再次获取锁而不会出现死锁。基于java.util.concurrent.locks.ReentrantLock实现可重入锁

五、要不要使用注解实现分布式锁?

现在有很多的博文里面给出了一种非常简单的实现,就是在方法上面加注解,比如:

@RedisLock("lock-key")
public void save(){
    
    

}

这种实现使用上非常简单,但是笔者不建议使用这种方式,有几个原因

  • 不管是什么锁,锁定的范围应该越小越好,琐能保证数据操作多线程安全性,但是会降低应用性能。能对1行代码加锁就完成的需求,就不要锁定2行。把注解加在方法上,是锁定了方法里面所有的代码执行,高并发场景会影响执行效率。(有的同学说可以把需要锁定的代码单独抽取函数,这的确是一个方法,但抽取的粒度过细会破坏代码的可维护性)
  • 使用注解的方式其核心原理是使用AOP面向切面编程的实现。异常及事务的处理、分布式锁在我们的应用里面都是面向切面编程的,混合到一起有的时候很难处理。我的建议是分布式锁它并不是一个“常用项”,如果你的项目里面到处都是分布式锁,你要思考一下是不是你的设计出了问题。所以对于非常用项我们没有必要过度封装,我们使用try-finally的方法来使用它就可以了,代码封装少可读性强,如果出现异常处理也都非常灵活,改动锁相关的代码影响面积小。

猜你喜欢

转载自blog.csdn.net/hanxiaotongtong/article/details/122906727
今日推荐