实现方法:使用redis的eval执行lua脚本
EVAL script numkeys key [key ...] arg [arg ...]
从 Redis 2.6.0 版本开始,通过内置的 Lua 解释器,可以使用 EVAL 命令对 Lua 脚本进行求值。
Java代码
package com.label.practice;
import com.google.common.collect.Lists;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.List;
/**
* Redis分布式锁
*
* @author libiao
* @since 2017-12-05
*/
@Log4j2
public class RedisClient {
private JedisPool jedisPool = null;
public long del(String... keys) {
try (Jedis jedis = jedisPool.getResource()) {
return jedis.del(keys);
}
}
public boolean set(String key, String value) {
try (Jedis jedis = jedisPool.getResource()) {
return StringUtils.equals(jedis.set(key, value), Constant.SET_SUCCESS);
}
}
public boolean setNxEx(String key, String value, int seconds) {
try (Jedis jedis = jedisPool.getResource()) {
return StringUtils.equals(jedis.set(key, value, Constant.SET_IF_NOT_EXISTS, Constant.SET_WITH_EXPIRES, seconds), Constant.SET_SUCCESS);
}
}
public String get(String key) {
try (Jedis jedis = jedisPool.getResource()) {
return jedis.get(key);
}
}
public Object eval(String script, List<String> keyList, List<String> valueList) {
try (Jedis jedis = jedisPool.getResource()) {
return jedis.eval(script, keyList, valueList);
}
}
public RedisLock getRedisLock() {
return new RedisLock();
}
public class RedisLock {
private static final String lockScript = "if (redis.call('exists',KEYS[1]) == 0 or redis.call('get',KEYS[1]) == ARGV[2]) then return redis.call('setex',KEYS[1],ARGV[1],ARGV[2]) else return -1 end";
public static final String unlockScript = "if (redis.call('exists',KEYS[1]) == 0 or redis.call('get',KEYS[1]) == ARGV[1]) then return redis.call('del',KEYS[1]) else return -1 end";
public boolean tryLock(String key, String requestId, int seconds) {
try (Jedis jedis = jedisPool.getResource()) {
Object eval = jedis.eval(lockScript, Lists.newArrayList(key), Lists.newArrayList(String.valueOf(seconds), requestId));
log.info(eval);
if (null != eval && StringUtils.equals(Constant.SET_SUCCESS, String.valueOf(eval))) {
return true;
}
}
return false;
}
public boolean unLock(String key, String requestId) {
try (Jedis jedis = jedisPool.getResource()) {
Object eval = jedis.eval(unlockScript, Lists.newArrayList(key), Lists.newArrayList(requestId));
log.info(eval);
if (null == eval) {
return false;
}
int affectedRows = Integer.parseInt(String.valueOf(eval));
if (1 == affectedRows || 0 == affectedRows) {
return true;
}
}
return false;
}
}
public class Constant {
public static final String SET_SUCCESS = "OK";
public static final String SET_IF_NOT_EXISTS = "NX";
public static final String SET_WITH_EXPIRES = "EX";
}
public static RedisClient getInstance() {
return RedisClientPlaceHolder.redisClient;
}
private RedisClient() {
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
poolConfig.setMaxIdle(10);
poolConfig.setMaxTotal(50);
poolConfig.setLifo(false);
poolConfig.setTestOnBorrow(true);
poolConfig.setTestWhileIdle(true);
poolConfig.setMaxWaitMillis(5000);
jedisPool = new JedisPool(poolConfig, "w10979.sit.wdds.redis.com", 10979);
}
private static class RedisClientPlaceHolder {
private static RedisClient redisClient = new RedisClient();
}
}