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


    在这里插入图片描述

    一、集成spring-integration-redis

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

    <dependency>
         <groupId>org.springframework.bootgroupId>
         <artifactId>spring-boot-starter-integrationartifactId>
    dependency>
    <dependency>
         <groupId>org.springframework.integrationgroupId>
         <artifactId>spring-integration-redisartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    二、注册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);
         }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    三、使用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();   //释放锁
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    四、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
    • 3
    • 4

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

    • 不管是什么锁,锁定的范围应该越小越好,琐能保证数据操作多线程安全性,但是会降低应用性能。能对1行代码加锁就完成的需求,就不要锁定2行。把注解加在方法上,是锁定了方法里面所有的代码执行,高并发场景会影响执行效率。(有的同学说可以把需要锁定的代码单独抽取函数,这的确是一个方法,但抽取的粒度过细会破坏代码的可维护性)
    • 使用注解的方式其核心原理是使用AOP面向切面编程的实现。异常及事务的处理、分布式锁在我们的应用里面都是面向切面编程的,混合到一起有的时候很难处理。我的建议是分布式锁它并不是一个“常用项”,如果你的项目里面到处都是分布式锁,你要思考一下是不是你的设计出了问题。所以对于非常用项我们没有必要过度封装,我们使用try-finally的方法来使用它就可以了,代码封装少可读性强,如果出现异常处理也都非常灵活,改动锁相关的代码影响面积小。
  • 相关阅读:
    手撕AVL树
    设计模式4、建造者模式 Builder
    关于医疗器械的算法、协议开发(五)
    ES的测试连通性
    1V1音视频实时互动直播系统
    编译opencv-3.4.5 [交叉编译]
    MAC 安装 maven
    RHEL 软件包管理 rpm yum 源码编译
    HTML5的语义元素
    Go :测试switch语句(附完整源码)
  • 原文地址:https://blog.csdn.net/hanxiaotongtong/article/details/122906727