目录

介绍

引入redis、redisson依赖

配置redis连接信息

配置RedisConfig

配置RedissonConfig

加解锁锁操作


redissonClient的示例 redisson使用教程_java

 

介绍

现在项目一般都是使用分布式集群部署,对后台业务数据的某些操作需要考虑加锁的问题,而jdk的synchronize加锁机制已经不适合做集群部署的操作,因为synchronize关键字只是针对于单体部署的单台虚拟机有用。考虑到现在系统使用redis做缓存比较高效,此处推荐使用redis下的分布式锁redisson进行加锁操作。而Redisson解决了Redis基于 setnx 实现的分布式锁存在的一些问题:

  • 不可重入:同一个线程无法多次获取同一把锁(eg:方法A调用方法B,在方法A中先获取锁,然后去调用方法B,方法B也需要获取同一把锁,这种情况下如果锁不可重入,方法B显然获取不到锁,会出现死锁的情况)
  • 不可重试:获取锁只尝试一次就返回 false,没有重试机制
  • 超时释放:超时释放虽然能够避免死锁,但如果业务执行执行时间较长导致锁释放,会存在安全隐患
  • 主从一致性:主从数据同步存在延迟,比如:线程在主节点获取了锁,尚未同步给从节点时主节点宕机,此时会选一个从节点作为新的主节点,这个从节点由于没有完成同步不存在锁的标识,此时其他线程可以趁虚而入拿到锁,这就造成多个线程同时拿到锁,就会出现安全问题)

引入redis、redisson依赖

<!--redis依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>2.3.2.RELEASE</version>
</dependency>
<!--redisson依赖-->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.16.4</version>
</dependency>
<!--使用redis时需要此jar包-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
配置redis连接信息
spring:
  redis:
    database: 0
    host: xx.xx.xx.xx
    port: 1316
    password: xxxx
    timeout: 3000
    lettuce:
      pool:
        max-active: 20
        max-idle: 10
        max-wait: -1
        min-idle: 0
配置RedisConfig
@Configuration
public class RedisConfig {


    Logger logger = LoggerFactory.getLogger(RedisConfig.class);


    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory) {
        logger.debug("redisTemplate实例化 {}");
        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer<Object>(Object.class);
        // key的序列化采用StringRedisSerializer
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        // value值的序列化采用fastJsonRedisSerializer
        redisTemplate.setValueSerializer(fastJsonRedisSerializer);
        // hash的key也采用String的序列化方式
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        // hash的value序列化方式采用fastJsonRedisSerializer
        redisTemplate.setHashValueSerializer(fastJsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}
配置RedissonConfig
配置RedissonClient客户端,用于加锁操作,使用@Bean注解,当程序启动时加载到spring容器中供后期使用,配置客户端需要根据redis服务的模式配置,有集群、主从、哨兵等模式,具体配置参考官网:2. 配置方法 · redisson/redisson Wiki · GitHub;此处使用的单节点模式配置。
@Configuration
public class RedissonConfig {


    //redis相关配置
    @Value("${spring.redis.host}")
    private String redisHost;


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


    @Value("${spring.redis.database}")
    private int database;


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


    @Value("${spring.redis.timeout}")
    private int timeout;


    //创建redisson客户端,此时默认使用单节点
    @Bean
    public RedissonClient redissonClient(){
        Config config = new Config();
        config.useSingleServer().setAddress("redis://"+redisHost+":"+redisPort);
        config.useSingleServer().setDatabase(database);
        config.useSingleServer().setPassword(password);
        config.useSingleServer().setTimeout(timeout);
        RedissonClient redisson = Redisson.create(config);
        return redisson;
    }
}
加解锁锁操作
 操作特别简单,通过RedissonClient获取锁,然后调用lock即可加锁,解锁使用unlock即可。
//在需要使用分布式锁的类里面注入RedissonClient客户端
@Autowired
RedissonClient redissonClient;


//根据锁名称获取锁
RLock lock = redissonClient.getLock("anyLock");


//加锁
// 最常见的使用方法
lock.lock();
// 加锁以后10秒钟自动解锁
lock.lock(10, TimeUnit.SECONDS);


// 尝试加锁,最多等待100秒,上锁以后10秒自动解锁
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
if (res) {
   try {
     ...
   } finally {
       //解锁
       lock.unlock();
   }
}