基于redis实现分布式锁

背景

基于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脚本来确保两步操作的原子性。

你可能感兴趣的:(分布式锁,redis)