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 原生的對象執(zhí)行l(wèi)ua腳本的話居暖,非常簡單子刮,也很直觀毙沾。但是真實的項目里煌恢,我們經常會使用Spring Cloud框架骇陈,該框架已經集成了 RedisTemplate 這個類,開放了很多對redis的api瑰抵。筆者在使用RedisTemplate執(zhí)行l(wèi)ua腳本你雌,遇到一些困難。摸索了一番二汛,最后解決了婿崭,趁此機會記錄下來。
RedisTemplate執(zhí)行l(wèi)ua
/**
* <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方式婿着。實現(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è)務類內即可提完。