Redis实现单机加锁解锁与集群加锁解锁

Redis实现单机加锁解锁

一、RedisUtil类

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
 * 分布式锁的工具类
 *
 * @date 2020-09-08
 */
@Component
public class RedisUtils {
    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";
    private static final Long RELEASE_SUCCESS = 1L;
    private static final int CONNECTION_TIME_OUT = 1000;
    private static final int SO_TIME_OUT = 5000;
    private static final int MAX_ATTEMPTS = 10;
    private static final Logger logger = LoggerFactory.getLogger(FileHelper.class);

	// 读取application文件中的redis密码
    @Value("${spring.redis.password}")
    private String password;
    // 读取application文件中的redis节点
    @Value("${spring.redis.cluster.nodes}")
    private String nodes;

    /**
     * 加锁
     *
     * @param jedis     jedis连接
     * @param key       锁的key
     * @param requestId 一个随机值,key对应的value
     * @return
     */
    public boolean tryLock(Jedis jedis, String key, String requestId) {
        String result = jedis.set(key, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, CONNECTION_TIME_OUT);
        if (LOCK_SUCCESS.equals(result)) {
            logger.info("加锁成功");
            return true;
        }
        return false;
    }

    /**
     * 解锁
     *
     * @param jedis     jedis
     * @param key       锁的key
     * @param requestId 一个随机值,key对应的value
     * @return
     */
    public boolean unLock(Jedis jedis, String key, String 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) jedis.eval(script, Collections.singletonList(key), Collections.singletonList(requestId));
        if (RELEASE_SUCCESS.equals(result)) {
            logger.info("解锁成功!");
            return true;
        }
        return false;
    }

    /**
     * 获取一个jedis
     *
     * @return
     */
    public Jedis getJedis() {
        Jedis jedis = new Jedis("redisIP","port");
        return jedis;
    }
}

二、测试类

    @Test
    public void test(){
        Jedis jedis = redisUtils.getJedis();
        String uuid = UUID.randomUUID().toString();
        try {
            boolean result = redisUtils.tryLock(jedis, key, uuid);
            if (result){
                // 执行逻辑代码
            }else {
                logger.info("自动生成假期失败");
            }
        }catch (Exception e){
            logger.error(e.getMessage(),e);
        }finally {
            if (!redisUtils.unLock(jedis,key,uuid)){
                throw new RuntimeException("release lock fail");
            }
        }
    }

Redis实现集群加锁解锁

一、redis配置类

import org.redisson.Redisson;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class RedissionConfig {
    private static Config config = new Config();
    private static RedissonClient redisson = null;
    private static final String RATOMIC_NAME = "genId_";
    @Value("${spring.redis.password}")
    private String password;
    @Value("${spring.redis.cluster.nodes}")
    private String nodes;

    public void init() {
        try {
            config.useClusterServers()
                    // 设置集群状态扫描间隔
                    .setScanInterval(200000)
                    // 设置对于master节点的连接池中连接数最大为10000
                    .setMasterConnectionPoolSize(10000)
                    // 设置对于slave节点的连接池中连接数最大为500
                    .setSlaveConnectionPoolSize(10000)
                    // 如果当前连接池里的连接数量超过了最小空闲连接数,而同时有连接空闲时间超过了该数值,那么这些连接将会自动被关闭,并从连接池里去掉。时间单位是毫秒。
                    .setIdleConnectionTimeout(10000)
                    // 同任何节点建立连接时的等待超时。时间单位是毫秒。
                    .setConnectTimeout(30000)
                    // 等待节点回复命令的时间。该时间从命令发送成功时开始计时。
                    .setTimeout(3000)
                    // 当与某个节点的连接断开时,等待与其重新建立连接的时间间隔。时间单位是毫秒。
                    .setRetryInterval(3000)
                    // redis连接密码
                    .setPassword(password);
            String[] split = nodes.split(",");
            // 加入redis集群
            for (int i = 0;i < split.length;i++) {
                config.useClusterServers().addNodeAddress(split[i]);
            }
            redisson = Redisson.create(config);
            RAtomicLong atomicLong = redisson.getAtomicLong(RATOMIC_NAME);
            // 自增设置为从0开始
            atomicLong.set(0);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public RedissonClient getRedisson() {
        // 初始化
        if (redisson == null) {
            init();
        }
        return redisson;
    }
}

二、redis 加锁与解锁

import com.vipkid.eim.hr.leave.config.RedissionConfig;
import org.redisson.RedissonLock;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.concurrent.TimeUnit;

public class RedissionLock {

    @Autowired
    private RedissionConfig redissionConfig;

    private static final Logger LOGGER = LoggerFactory.getLogger(RedissonLock.class);

    private RedissonClient redissonClient = redissionConfig.getRedisson();


    public void lock(String key) {
        RLock myLock = redissonClient.getLock(key);
        // lock提供带timeout参数,timeout结束强制解锁,防止死锁
        myLock.lock(2, TimeUnit.SECONDS);
        System.err.println("======lock======" + Thread.currentThread().getName());
    }

    public void unLock(String key) {
        RLock myLock = redissonClient.getLock(key);
        myLock.unlock();
        System.err.println("======unlock======" + Thread.currentThread().getName());
    }
}

三、测试类

@Override
    public void test(){
        try {
            redissionLock.lock(key);
            // 执行逻辑代码
        }catch (Exception e){
            logger.error(e.getMessage(),e);
        }finally {
            redissionLock.unLock(key);
        }
    }

你可能感兴趣的:(Java)