zoukankan      html  css  js  c++  java
  • redis分布式锁

    1. redis分布式锁

    1.1. 实现工具

    public class RedisTool {
     
        private static final String LOCK_SUCCESS = "OK";
        private static final String SET_IF_NOT_EXIST = "NX";
        private static final String SET_WITH_EXPIRE_TIME = "PX";
        private static final Long RELEASE_SUCCESS = 1L;
    
        /**
         * 尝试获取分布式锁
         * @param jedis Redis客户端
         * @param lockKey 锁
         * @param requestId 请求标识
         * @param expireTime 超期时间
         * @return 是否获取成功
         */
        public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
     
            String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
     
            if (LOCK_SUCCESS.equals(result)) {
                return true;
            }
            return false;
     
        }
    
    
        /**
         * 释放分布式锁
         * @param jedis Redis客户端
         * @param lockKey 锁
         * @param requestId 请求标识
         * @return 是否释放成功
         */
        public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {
    
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
    
            if (RELEASE_SUCCESS.equals(result)) {
                return true;
            }
            return false;
    
        }
     
    }
    

    1.2. redis配置

    package com.zhiyis.common.config;
    
    import com.fasterxml.jackson.annotation.JsonAutoDetect;
    import com.fasterxml.jackson.annotation.PropertyAccessor;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cache.CacheManager;
    import org.springframework.cache.annotation.CachingConfigurerSupport;
    import org.springframework.cache.annotation.EnableCaching;
    import org.springframework.cache.interceptor.KeyGenerator;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.cache.RedisCacheManager;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
    import redis.clients.jedis.JedisPool;
    import redis.clients.jedis.JedisPoolConfig;
    
    import java.lang.reflect.Method;
    
    
    @Configuration
    @EnableCaching
    public class RedisConfig extends CachingConfigurerSupport {
    
        private static Logger logger = LoggerFactory.getLogger(RedisConfig.class);
    
        @Value("${spring.redis.host}")
        private String redisHost;
    
        @Value("${spring.redis.port}")
        private int redisPort;
    
        @Value("${spring.redis.timeout}")
        private int redisTimeout;
    
        @Value("${spring.redis.password}")
        private String redisAuth;
    
        @Value("${spring.redis.database}")
        private int redisDb;
    
        @Value("${spring.redis.pool.max-active}")
        private int maxActive;
    
        @Value("${spring.redis.pool.max-wait}")
        private int maxWait;
    
        @Value("${spring.redis.pool.max-idle}")
        private int maxIdle;
    
        @Value("${spring.redis.pool.min-idle}")
        private int minIdle;
    
        @Bean
        @Override
        public KeyGenerator keyGenerator() {
            return new KeyGenerator() {
                @Override
                public Object generate(Object target, Method method, Object... params) {
                    StringBuilder sb = new StringBuilder();
                    sb.append(target.getClass().getName());
                    sb.append(method.getName());
                    for (Object obj : params) {
                        sb.append(obj.toString());
                    }
                    return sb.toString();
                }
            };
        }
    
        @Bean
        public CacheManager redisCacheManager() {
            RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate());
            //默认300秒过期
            cacheManager.setDefaultExpiration(300);
            // 启动时加载远程缓存
            cacheManager.setLoadRemoteCachesOnStartup(true);
            //是否使用前缀生成器
            cacheManager.setUsePrefix(true);
            return cacheManager;
        }
    
    
    
        @Bean
        public RedisConnectionFactory redisConnectionFactory() {
            JedisPoolConfig poolConfig = new JedisPoolConfig();
            poolConfig.setMaxTotal(maxActive);
            poolConfig.setMaxIdle(maxIdle);
            poolConfig.setMaxWaitMillis(maxWait);
            poolConfig.setMinIdle(minIdle);
            poolConfig.setTestOnBorrow(true);
            poolConfig.setTestOnReturn(false);
            poolConfig.setTestWhileIdle(true);
            JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(poolConfig);
            jedisConnectionFactory.setPassword(redisAuth);
            jedisConnectionFactory.setHostName(redisHost);
            jedisConnectionFactory.setDatabase(redisDb);
            jedisConnectionFactory.setPort(redisPort);
            jedisConnectionFactory.setTimeout(redisTimeout);
            return jedisConnectionFactory;
        }
    
        @Bean
        public RedisTemplate<String, Object> redisTemplate() {
            RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
            Jackson2JsonRedisSerializer<Object> serializer = jackson2JsonRedisSerializer();
            redisTemplate.setConnectionFactory(redisConnectionFactory());
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            redisTemplate.setValueSerializer(serializer);
            redisTemplate.setHashKeySerializer(new StringRedisSerializer());
            redisTemplate.setHashValueSerializer(serializer);
            return redisTemplate;
        }
    
        @Bean
        public Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer() {
            final Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
            final ObjectMapper objectMapper = Jackson2ObjectMapperBuilder
                    .json().build();
            objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
            jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
            return jackson2JsonRedisSerializer;
        }
    
        @Bean
        public JedisPool redisPoolFactory() throws Exception {
            JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
            jedisPoolConfig.setMaxIdle(maxIdle);
            jedisPoolConfig.setMaxWaitMillis(maxWait);
            // 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true
            jedisPoolConfig.setBlockWhenExhausted(true);
            // 是否启用pool的jmx管理功能, 默认true
            jedisPoolConfig.setJmxEnabled(true);
            JedisPool jedisPool = new JedisPool(jedisPoolConfig, redisHost, redisPort, redisTimeout, redisAuth);
            return jedisPool;
        }
    }
    
    

    上述主要用到 redisPoolFactory方法,用来初始化jedispool,缓存等不需要用到可以删除

    1.3. 使用aop用注解的形式来进行分布式锁的包裹

    /**
     * redis分布式锁注解
     * @author laoliangliang
     * @date 2019/2/20 10:27
     */
    public @interface JedisLock {
    }
    
    package com.zhiyis.framework.aop;
    
    import com.zhiyis.common.utils.RedisTool;
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    
    import java.lang.reflect.Method;
    import java.util.UUID;
    
    /**
     * redis分布式锁aop实现
     *
     * @author laoliangliang
     * @date 2019/1/10 17:04
     */
    @Slf4j
    @Component
    @Aspect
    public class JedisLockAspect {
    
        @Pointcut(value = "(execution(* *.*(..)) && @annotation(com.zhiyis.framework.annotation.JedisLock))")
        private void pointcut() {
        }
    
        @Autowired
        private JedisPool jedisPool;
    
        @Around("pointcut()")
        public Object lockAroud(ProceedingJoinPoint joinPoint) throws Throwable {
    
            //获取切入方法的数据
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            //获取切入方法
            Method method = signature.getMethod();
            String lockKey = method.getName();
            String uuid = UUID.randomUUID().toString();
            try (Jedis jedis = jedisPool.getResource()) {
                boolean lock = RedisTool.tryGetDistributedLock(jedis, lockKey, uuid, 60000);
                if (lock) {
                    Object proceed = joinPoint.proceed();
                    RedisTool.releaseDistributedLock(jedis, lockKey, uuid);
                    return proceed;
                }
            } catch (Throwable e) {
                log.error("tradeCode接口错误", e);
                throw e;
            }
            return null;
        }
    
    
    }
    
    
    

    使用

    1. 使用就很简单了,在要使用分布式锁的方法上面直接加上 @JedisLock 注解

    参考 https://www.cnblogs.com/linjiqin/p/8003838.html

  • 相关阅读:
    P1030 求先序排列 P1305 新二叉树
    spfa
    Clairewd’s message ekmp
    Cyclic Nacklace hdu3746 kmp 最小循环节
    P1233 木棍加工 dp LIS
    P1052 过河 线性dp 路径压缩
    Best Reward 拓展kmp
    Period kmp
    Substrings kmp
    Count the string kmp
  • 原文地址:https://www.cnblogs.com/sky-chen/p/10375142.html
Copyright © 2011-2022 走看看