RedisTemplate使用lua腳本分布式鎖

Jedis進(jìn)行分布式鎖

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 原生的對象執(zhí)行l(wèi)ua腳本的話,非常簡單,也很直觀。但是真實(shí)的項(xiàng)目里,我們經(jīng)常會使用Spring Cloud框架,該框架已經(jīng)集成了 RedisTemplate 這個(gè)類,開放了很多對redis的api。筆者在使用RedisTemplate執(zhí)行l(wèi)ua腳本,遇到一些困難。摸索了一番,最后解決了,趁此機(jī)會記錄下來。

RedisTemplate執(zhí)行l(wèi)ua

/**
 * <p>
 * 分布式鎖定義
 * </p>
 *
 */
public interface DistributedLock {

    /**
     * <p>
     *     上鎖,默認(rèn)的鎖的時(shí)間是 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方式。實(shí)現(xiàn)類如下:

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 注入到所需要使用的業(yè)務(wù)類內(nèi)即可。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容