基于redisson实现分布式锁

  在日常业务开发中,为了解决并发问题,比如,同一个时刻,多笔相同订单号的订单同时请求,我们只会受理一笔,其他的请求拒绝。我们通常都是用分布锁来解决,当然,也可以使用数据库的唯一索引来解决,数据新增的时候会报插入异常,这样如果系统并发很大,会给数据库造成很大的压力,通常都不会这么操作。
  实现分布式锁的方案有很多种,比如用 zookeeper、redis等中间件,本文主要介绍使用 redission 实现分布锁,主要原因有以下几点:

  • 生产有redis 哨兵集群,不需要在部署其他中间件环境
  • redission 有看门狗机制,能自动给分布式锁延期(这个可以网上搜索参考其他文章)

一、环境说明

maven 依赖

<dependency>    <groupId>org.springframework.boot</groupId>     <artifactId>spring-boot-starter-parent</artifactId>     <version>2.1.2.RELEASE</version> </dependency>  <dependency>   <groupId>org.redisson</groupId>   <artifactId>redisson-spring-boot-starter</artifactId>   <version>3.11.2</version> </dependency> 

二、代码实现

@Configuration @Setter @ConfigurationProperties(prefix = spring.redis.lettuce.pool) public class RedisClientConfig {    @Value(${redis.clusterName})     private String clusterName;      @Value(${redis1.host})     private String redis1Host;      @Value(${redis1.port})     private Integer redis1Port;      @Value(${redis2.host})     private String redis2Host;      @Value(${redis2.port})     private Integer redis2Port;       @Value(${redis3.host})     private String redis3Host;      @Value(${redis3.port})     private Integer redis3Port;      @Bean     public RedissonClient redissonClient() {         Config config = new Config();         config.useSentinelServers()                 .setMasterName(clusterName)                 .addSentinelAddress(redis://+redis1Host+:+redis1Port)                 .addSentinelAddress(redis://+redis2Host+:+redis2Port)                 .addSentinelAddress(redis://+redis3Host+:+redis3Port);         return Redisson.create(config);     }  } 
/**  * redis 分布式锁  */ @Component @Slf4j public class RedisLock {      @Autowired     private RedissonClient redissonClient;      /**      *  尝试拿锁 waitTime 后停止重试,返回false      * @param lockKey 锁key值      * @param unit  时间单位      * @param waitTime  等待时间      * @return 是否获取锁成功      */     public boolean tryLock(String lockKey, long waitTime,long leaseTime,TimeUnit unit) {         RLock lock = redissonClient.getLock(lockKey);         try {             return lock.tryLock(waitTime,leaseTime, unit);         } catch (InterruptedException e) {             log.error(获取redis分布式锁异常,e);             return false;         }     }      /**      * 尝试拿锁,不重试,获取不到,返回false      * 具有Watch Dog 自动延期机制 默认续30s      * @param lockKey      * @return      */     public boolean tryLock(String lockKey) {         RLock lock = redissonClient.getLock(lockKey);         try {             return lock.tryLock(0L, TimeUnit.SECONDS);         } catch (InterruptedException e) {             log.error(获取redis分布式锁异常,e);             return false;         }     }      /**      * 释放锁      * @param lockKey      */     public void unlock(String lockKey) {         try {             RLock lock = redissonClient.getLock(lockKey);             if(lock.isLocked()){                 lock.unlock();             }         } catch (Exception e) {             log.error(释放锁异常,e);         }     }  }