也有不用回调函数直接调用脚本的版本,但是经过我的测试之后,发现报错EvalSha is not supported in cluster environment
上锁解锁的代码比较简单,也好理解。利用lua脚本解释redis命令,保证命令一次性运行成功,从而保证命令执行的原子性。
但是想和业务系统结合起来还是有难度的。特别是在本地事务中去使用的时候,需要结合业务特点,本地事务提交之后解锁也要成功。
/**
* 获取锁
* @param lockKey
* @param value
* @param expireTime:单位-秒
* @return
*/
public static boolean getLock(String lockKey, String requestId, int expireTime) {
boolean ret = false;
try {
List<String> keys = new ArrayList<String>();
keys.add(lockKey);
List<String> args = new ArrayList<String>();
args.add(requestId);
args.add(expireTime + "");
String script = "if redis.call('setNx',KEYS[1],ARGV[1])==1 then return redis.call('expire',KEYS[1],ARGV[2]) else return 0 end";
Long result = (Long) redisTemplate.execute(new RedisCallback<Long>() {
@Override
public Long doInRedis(RedisConnection connection) throws DataAccessException {
Object nativeConnection = connection.getNativeConnection();
// 集群模式和单机模式虽然执行脚本的方法一样,但是没有共同的接口,所以只能分开执行
// 集群模式
if (nativeConnection instanceof JedisCluster) {
return (Long) ((JedisCluster) nativeConnection).eval(script, keys, args);
}
// 单机模式
else if (nativeConnection instanceof Jedis) {
return (Long) ((Jedis) nativeConnection).eval(script, keys, args);
}
return 0L;
}
});
if (SUCCESS.equals(result)) {
log.info("加锁成功...");
return true;
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return ret;
}
/**
* 释放锁
*
* @param lockKey
* @param value
* @return
*/
public static boolean releaseLock(String lockKey, String requestId) {
boolean ret = false;
try {
List<String> keys = new ArrayList<String>();
keys.add(lockKey);
List<String> args = new ArrayList<String>();
args.add(requestId);
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Long result = (Long) redisTemplate.execute(new RedisCallback<Long>() {
@Override
public Long doInRedis(RedisConnection connection) throws DataAccessException {
Object nativeConnection = connection.getNativeConnection();
if (nativeConnection instanceof JedisCluster) {
return (Long) ((JedisCluster) nativeConnection).eval(script, keys, args);
}
else if (nativeConnection instanceof Jedis) {
return (Long) ((Jedis) nativeConnection).eval(script, keys, args);
}
return 0L;
}
});
if (SUCCESS.equals(result)) {
log.info("解锁成功...");
return true;
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return ret;
}
以上代码集群版本已经过测试。单机版未测试。
来源:oschina
链接:https://my.oschina.net/osokra/blog/4445512