RedisTemplate使用lua脚本分布式锁

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

/**
 * 

* 分布式锁定义 *

* */ public interface DistributedLock { /** *

* 上锁,默认的锁的时间是 10s *

*/ boolean lock(String lock, String val); /** *

* 上锁 *

*/ boolean lock(String lock, String val, int second); /** *

* 释放锁 *

*/ void unlock(String lock, String val); }

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

public class RedisLock implements DistributedLock {

    public static final int DEFAULT_SECOND_LEN = 10; // 10 s

    private RedisTemplate 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 argsSerializer;
    private RedisSerializer resultSerializer;

    /**
     * 初始化lua 脚本
     */
    public void init(RedisTemplate 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 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 keys = Collections.singletonList(lock);
        redisTemplate.execute(unLockRedisScript, argsSerializer, resultSerializer, keys, val);
    }


}

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

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

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

你可能感兴趣的:(RedisTemplate使用lua脚本分布式锁)