美文网首页Redis
RedisTemplate使用lua脚本分布式锁

RedisTemplate使用lua脚本分布式锁

作者: f22448cd5541 | 来源:发表于2019-06-19 16:55 被阅读0次

    Jedis进行分布式锁

    Object obj = jedis.eval("if redis.call('setnx', KEYS[1], ARGV[1]) == 1 then redis.call('expire', KEYS[1], ARGV[2]) return 'true' else return 'false' end", 1, lock, val, "10");
    

    我们使用 jedis 原生的对象执行lua脚本的话,非常简单,也很直观。但是真实的项目里,我们经常会使用Spring Cloud框架,该框架已经集成了 RedisTemplate 这个类,开放了很多对redis的api。笔者在使用RedisTemplate执行lua脚本,遇到一些困难。摸索了一番,最后解决了,趁此机会记录下来。

    RedisTemplate执行lua

    /**
     * <p>
     * 分布式锁定义
     * </p>
     *
     */
    public interface DistributedLock {
    
        /**
         * <p>
         *     上锁,默认的锁的时间是 10s
         * </p>
         */
        boolean lock(String lock, String val);
    
        /**
         * <p>
         *     上锁
         * </p>
         */
        boolean lock(String lock, String val, int second);
    
        /**
         * <p>
         *     释放锁
         * </p>
         */
        void unlock(String lock, String val);
    }
    

    这里,序列化的方式,采用的都是String方式。实现类如下:

    public class RedisLock implements DistributedLock {
    
        public static final int DEFAULT_SECOND_LEN = 10; // 10 s
    
        private RedisTemplate<String, String> redisTemplate;
    
        private static final String LOCK_LUA = "if redis.call('setnx', KEYS[1], ARGV[1]) == 1 then redis.call('expire', KEYS[1], ARGV[2]) return 'true' else return 'false' end";
        private static final String UNLOCK_LUA = "if redis.call('get', KEYS[1]) == ARGV[1] then redis.call('del', KEYS[1]) end return 'true' ";
    
        private RedisScript lockRedisScript;
        private RedisScript unLockRedisScript;
    
        private RedisSerializer<String> argsSerializer;
        private RedisSerializer<String> resultSerializer;
    
        /**
         * 初始化lua 脚本
         */
        public void init(RedisTemplate<String, String> redisTemplate) {
    
            this.redisTemplate = redisTemplate;
    
            argsSerializer = new StringRedisSerializer();
            resultSerializer = new StringRedisSerializer();
    
            lockRedisScript = RedisScript.of(LOCK_LUA, String.class);
            unLockRedisScript = RedisScript.of(UNLOCK_LUA, String.class);
        }
    
        @Override
        public boolean lock(String lock, String val) {
            return this.lock(lock, val, DEFAULT_SECOND_LEN);
        }
    
        @Override
        public boolean lock(String lock, String val, int second) {
            List<String> keys = Collections.singletonList(lock);
            String flag = redisTemplate.execute(lockRedisScript, argsSerializer, resultSerializer, keys, val, String.valueOf(second));
            return Boolean.valueOf(flag);
        }
    
        @Override
        public void unlock(String lock, String val) {
            List<String> keys = Collections.singletonList(lock);
            redisTemplate.execute(unLockRedisScript, argsSerializer, resultSerializer, keys, val);
        }
    
    
    }
    

    使用如下,需要先将该类初始化到Spring容器里,如下:

    @Bean
    public RedisLock redisLock(RedisTemplate<String, String> redisTemplate) {
       RedisLock redisLock = new RedisLock();
       redisLock.init(redisTemplate);
       return redisLock;
    }
    

    使用该锁对象,只需要将 RedisLock 注入到所需要使用的业务类内即可。

    相关文章

      网友评论

        本文标题:RedisTemplate使用lua脚本分布式锁

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