美文网首页
基于RedisTemplate的分布式共享锁

基于RedisTemplate的分布式共享锁

作者: 安宁_2088 | 来源:发表于2020-08-06 14:15 被阅读0次

    此文档主要演示了如何使用 Spring Boot 集成RedisTemplate实现分布式锁。

    application.yml

    spring:
      redis:
        host: localhost
        # 连接超时时间(记得添加单位,Duration)
        timeout: 10000ms
        # Redis默认情况下有16个分片,这里配置具体使用的分片
        # database: 0
        lettuce:
          pool:
            # 连接池最大连接数(使用负值表示没有限制) 默认 8
            max-active: 8
            # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
            max-wait: -1ms
            # 连接池中的最大空闲连接 默认 8
            max-idle: 8
            # 连接池中的最小空闲连接 默认 0
            min-idle: 0
    

    pom.xml

    基于 Spring Boot 引入redis

    <!-- redis -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <!-- 对象池,使用redis时必须引入 -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
    </dependency>
    

    RedisConfig

    基于Spring Boot 的 redis配置

    /**
     * redis配置
     * @author xiehengxing
     * @date 2020/7/29 18:30
     */
    @Configuration
    @AutoConfigureAfter(RedisAutoConfiguration.class)
    @EnableCaching
    public class RedisConfig {
    
        /**
         * 默认情况下的模板只能支持RedisTemplate<String, String>,也就是只能存入字符串,因此支持序列化
         */
        @Bean
        public RedisTemplate<String, Serializable> redisCacheTemplate(LettuceConnectionFactory redisConnectionFactory) {
            RedisTemplate<String, Serializable> template = new RedisTemplate<>();
            template.setKeySerializer(new StringRedisSerializer());
            template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
            template.setConnectionFactory(redisConnectionFactory);
            return template;
        }
    
        /**
         * 配置使用注解的时候缓存配置,默认是序列化反序列化的形式,加上此配置则为 json 形式
         */
        @Bean
        public CacheManager cacheManager(RedisConnectionFactory factory) {
            // 配置序列化
            RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
            RedisCacheConfiguration redisCacheConfiguration = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
    
            return RedisCacheManager.builder(factory).cacheDefaults(redisCacheConfiguration).build();
        }
    }
    
    

    RedisLock

    分布式共享锁的实现

    /**
     * 分布式共享锁
     * @author xiehengxing
     * @date 2020/8/2 10:40
     */
    @Slf4j
    @Component
    public class RedisLock {
    
        @Autowired
        private RedisTemplate redisTemplate;
    
        /**
         * 共享锁默认时长(秒)
         */
        private static final long TIMEOUT = 60;
        /**
         * 超时时长(秒)
         */
        private static final long OVERTIME = 6;
    
        /**
         * 获取锁
         * @param key
         * @param requestId
         * @return
         */
        public boolean lock(String key, String requestId){
            long startTime = System.currentTimeMillis();
            for(;;) {
                boolean locked = redisTemplate.opsForValue().setIfAbsent(key, requestId, TIMEOUT, TimeUnit.SECONDS);
                if (locked) {
                    return true;
                }
                if ((System.currentTimeMillis() - startTime)/1000 > OVERTIME) {
                    return false;
                }
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    log.error("线程被中断" + Thread.currentThread().getId(), e);
                }
            }
        }
    
    
        /**
         * 使用lua脚本解锁
         * @param key
         * @param requestId
         * @return
         */
        public boolean unlock(String key, String requestId) {
            if (StringUtils.isEmpty(key) || StringUtils.isEmpty(requestId)){
                return false;
            }
            DefaultRedisScript<Long> redisScript = new DefaultRedisScript();
            //用于解锁的lua脚本位置
            redisScript.setScriptText(
                    "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                        "return redis.call('del', KEYS[1]) " +
                    "else " +
                        "return 0" +
                    "end");
            redisScript.setResultType(Long.class);
    
            //没有指定序列化方式,默认使用上面配置的
            Object result = redisTemplate.execute(redisScript, Collections.singletonList(key), requestId);
            return result.equals(Long.valueOf(1));
        }
    }
    
    

    相关文章

      网友评论

          本文标题:基于RedisTemplate的分布式共享锁

          本文链接:https://www.haomeiwen.com/subject/oeeorktx.html