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 注入到所需要使用的业务类内即可。
网友评论