背景
基于redis实现。
代码
package xxx.trade.util;
import xxx.core.exception.BizException;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import redis.clients.jedis.JedisCluster;
import java.util.Collections;
public class JedisUtil {
private static final Logger LOGGER = LoggerFactory
.getLogger(JedisUtil.class);
private static JedisCluster jedisCluster;
private static final String PREFIX="xxx-callback:";
public JedisUtil() {
// do nothing
}
public static boolean lock(String key , String value , String nxx, Long lockExpireTimeOut) {
if (StringUtils.isBlank(key)) {
throw new BizException("key must not null!");
} else {
LOGGER.info("JedisTemplate:get cache key={},value={}", key, value);
String result = jedisCluster.set(PREFIX+key ,value,nxx,"EX",lockExpireTimeOut);
if ("OK".equals(result)) {
return true;
}
return false;
}
}
public static boolean unlock(String key, String value) {
try {
String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = jedisCluster.eval(luaScript, Collections.singletonList(PREFIX + key),
Collections.singletonList(value));
if (!"0".equals(result.toString())) {
return true;
}
} catch (Exception ex) {
LOGGER.error("unlock error");
}
return false;
}
static {
ApplicationContext context = new ClassPathXmlApplicationContext(new String[]
{"conf/springconf/redis/redis-spring-context.xml"});
jedisCluster = (JedisCluster)context.getBean("jedisClusterConfigA");
}
}
使用
主要是两步
1.获取锁
2.释放锁
代码
try{
获取锁;
处理业务;
} finally{
释放锁;
}
核心
是基于redis的set命令。
超时
为什么要设置超时?因为怕断电这种情况,导致获取锁之后,一直没有释放,导致其他的服务都获取不了锁。
断电之后,释放锁的代码,就没执行。
lua
为什么要用Lua,因为是lua脚本原子操作。
而删除的时候,包含两步
1.先读 //先检验redis是否有数据
2.后写 //如果没有,就删除数据
所以,释放锁的代码使用了lua脚本来确保两步操作的原子性。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。