基于Redis分布式锁Redisson及SpringBoot集成Redisson

 

- 分布式锁需要具备的条件和刚需

  • 独占性:OnlyOne,任何时刻只能有且仅有一个线程持有
  • 高可用:若redis集群环境下,不能因为某一个节点挂了而出现获取锁和释放锁失败的情况
  • 防死锁:杜绝死锁,必须有超时控制机制或者撤销操作,有个兜底终止跳出方案
  • 不乱抢:防止张冠李戴,不能私下unlock别人的锁,只能自己加锁自己释放
  • 重入性:同一个节点的同一个线程如果获得锁之后,它也可以再次获取这个锁

 

- Redisson使用

引入redisson依赖:

<dependency>
  <groupId>org.redisson</groupId>
  <artifactId>redisson</artifactId>
  <version>3.16.2</version>
</dependency>

添加redisson配置:

import org.redisson.Redisson;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.io.Serializable;

@Configuration
public class RedisConfig {
  @Bean
  public RedisTemplate<String, Serializable> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
      RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();
      redisTemplate.setConnectionFactory(lettuceConnectionFactory);
      // 设置key序列号方式string
      redisTemplate.setKeySerializer(new StringRedisSerializer());
      // 设置value的序列化方式json
      redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
      redisTemplate.setHashKeySerializer(new StringRedisSerializer());
      redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
      redisTemplate.afterPropertiesSet();
      return redisTemplate;
  }
  @Bean
  public Redisson redisson() {
      Config config = new Config();
      config.useSingleServer().setAddress("redis://192.168.10.233:6379").setDatabase(0);
      return (Redisson) Redisson.create(config);
  }

}

接口测试:

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {

  @Autowired
  private StringRedisTemplate stringRedisTemplate;
  @Autowired
  private Redisson redisson;

  private static final String KEY = "spike";

  @GetMapping("/buy")
  public String bugGood() {
      RLock redissonLock = redisson.getLock(KEY);
      redissonLock.lock();
      try {
          String result = stringRedisTemplate.opsForValue().get("goods:001");
          int goodNumber = result == null ? 0 : Integer.parseInt(result);
          if (goodNumber > 0) {
              int realNum = goodNumber - 1;
              stringRedisTemplate.opsForValue().set("goods:001", realNum + "");
              return "秒杀成功,剩余库存:" + realNum;
          }
          return "商品已售罄!";
      } finally {
          redissonLock.unlock();
      }
  }

}

多节点的情况下,代码相同,要保证lock的key一样

 

- SpringBoot集成Redisson

引入 redis 和 redisson starter:

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.redisson/redisson -->
<dependency>
  <groupId>org.redisson</groupId>
  <artifactId>redisson-spring-boot-starter</artifactId>
</dependency>

redis 配置:

spring:
redis:
  # 地址
  host: 192.168.20.26
  # 端口,默认为6379
  port: 6379
  password: 123456
  # 连接超时时间
  timeout: 30s
  database: 0
  lettuce:
    pool:
      # 连接池中的最小空闲连接
      min-idle: 0
      # 连接池中的最大空闲连接
      max-idle: 8
      # 连接池的最大数据库连接数
      max-active: 8
      # #连接池最大阻塞等待时间(使用负值表示没有限制)
      max-wait: -1ms

redisson配置:

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.redisson.config.TransportMode;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* redisson配置
*/
@Configuration
public class RedissonConfig {

  @Value("${spring.redis.host}")
  private String host;
  @Value("${spring.redis.port}")
  private String port;
  @Value("${spring.redis.password}")
  private String password;

  @Bean
  public RedissonClient redissonClient() {
      Config config = new Config();
      config.setTransportMode(TransportMode.NIO);
      // 单体配置,如果是SSL连接,使用 rediss://
      SingleServerConfig singleServerConfig = config.useSingleServer();
      singleServerConfig.setAddress("redis://" + host + ":" + port);
      singleServerConfig.setPassword(password);
      return Redisson.create(config);
  }
}

使用:

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
public class TestController {

  @Resource
  private RedissonClient redissonClient;

  public void doAction1() {
      String lockKey = "lockKey";
      RLock lock = redissonClient.getLock(lockKey);
      // 加锁,无参数
      lock.lock();
      // 锁有效时间,时间单位
      // lock.lock(5, TimeUnit.SECONDS);
      try {
          // do something
      } finally {
          // 解锁
          lock.unlock();
      }
  }
  public void doAction2() throws InterruptedException {
      String lockKey = "lockKey";
      RLock lock = redissonClient.getLock(lockKey);
      // 1. 无参数,直接上锁
      // lock.tryLock();
      // 2. 等待时间,时间单位
      // lock.tryLock(3, TimeUnit.SECONDS);
      // 3. 等待时间,锁有效时间,时间单位
      // lock.tryLock(3, 5, TimeUnit.SECONDS);
      try {
          // 常规写法
          if (lock.tryLock(3, 5, TimeUnit.SECONDS)) {
              // do something
          } else {
              // 没有获取到锁
          }
      } finally {
          // 解锁
          lock.unlock();
      }
  }

}

关于基于Redis分布式锁Redisson及SpringBoot集成Redisson的文章就介绍至此,更多相关Redis分布式锁内容请搜索编程宝库以前的文章,希望以后支持编程宝库

 抽象工厂模式概述抽象工厂模式(Abastract Factory Pattern)属于创建型模式,它提供了一种创建对象的最佳方式。它提供一个创建一系列相关 ...