redis實現分佈式鎖(springboot中測試)

pom依賴

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <!-- jedis -->
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>2.8.2</version>
    </dependency>
</dependencies>

application.properties配置

#redis 配置
# Redis數據庫索引(默認爲0)
spring.redis.database=0
# Redis服務器地址
spring.redis.host=192.168.252.128
# Redis服務器連接端口
spring.redis.port=6379
# Redis服務器連接密碼(默認爲空)
spring.redis.password=123456
# 連接池最大連接數(使用負值表示沒有限制)
spring.redis.jedis.pool.max-active=200
# 連接池最大阻塞等待時間(使用負值表示沒有限制)
spring.redis.jedis.pool.max-wait=-1
# 連接池中的最大空閒連接
spring.redis.jedis.pool.max-idle=8
# 連接池中的最小空閒連接
spring.redis.jedis.pool.min-idle=0
# 連接超時時間(毫秒)
spring.redis.timeout=0
#spring-session 使用
spring.session.store-type=none

配置類

package com.example.demoredis.conf;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

@Configuration
public class RedisConfig {
    private Logger logger = LoggerFactory.getLogger(RedisConfig.class);
    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.password}")
    private String password;
    @Value("${spring.redis.port}")
    private int port;
    @Value("${spring.redis.timeout}")
    private int timeout;
    @Value("${spring.redis.jedis.pool.max-active}")
    private int maxActive;
    @Value("${spring.redis.jedis.pool.max-idle}")
    private int maxIdle;
    @Value("${spring.redis.jedis.pool.min-idle}")
    private int minIdle;
    @Value("${spring.redis.jedis.pool.max-wait}")
    private long maxWaitMillis;

    @Bean
    public JedisPool redisPoolFactory() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
        jedisPoolConfig.setMaxTotal(maxActive);
        jedisPoolConfig.setMinIdle(minIdle);
        JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, password);

        logger.info("JedisPool注入成功!");
        logger.info("redis地址:" + host + ":" + port);
        return jedisPool;
    }
}

測試代碼:

package com.example.demoredis;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.UUID;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoRedisApplicationTests {
    @Resource
    private JedisPool jedisPool;

    /**
     * @description 分佈式鎖測試
     * @date 14:57 2019/9/17
     **/
    @Test
    public void contextLoads() {
        Jedis jedis = jedisPool.getResource();
        String ping = jedis.ping();
        System.out.println("================================jedis連接:" + ping);
        /*System.out.println(lock(jedis, "a", "1", 60L));
        System.out.println(jedis.get("a"));
        System.out.println(unLock(jedis, "a", "2"));*/
        String key = "aaa";
        String value = UUID.randomUUID().toString().replaceAll("-", "");
        // 鎖定過期時間 s
        Long lockTime = 60L;
        // 嘗試次數
        Integer tryCount = 20;
        // 每次嘗試休閒時間 ms
        Long trySleepTime = 1500L;
        // 業務代碼執行時間 s
        Integer serSecond = 30;

        Boolean lock = false;
        try {
            lock = lockRetry(jedis, key, value, lockTime, tryCount, trySleepTime);
            if (lock) {
                System.out.println("鎖定成功-------------------------");
                System.out.println("業務代碼執行.......................................");
                for (int i = 0; i < serSecond; i++) {
                    System.out.println(" ... " + (i + 1));
                    Thread.sleep(1000L);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (lock) {
                Boolean unLock = unLock(jedis, key, value);
                if (unLock) {
                    System.out.println("解鎖成功-------------------------");
                } else {
                    System.out.println("解鎖失敗-------------------------");
                }
            }
        }
        System.out.println("=================  關閉連接  ==================");
        jedis.close();
    }

    /**
     * @description 重試去獲取鎖(鎖定)
     * 參數:jedis,k,v, 過期時間,重試次數,每次重試休眠時間
     * @date 14:58 2019/9/17
     **/
    public Boolean lockRetry(Jedis jedis, String key, String value, Long timeOut, Integer retry, Long sleepTime) {
        Boolean flag = false;
        try {
            for (int i = 0; i < retry; i++) {
                flag = lock(jedis, key, value, timeOut);
                System.out.println("重試" + (i + 1) + "次....... " + key + " -> " + value);
                if (flag) {
                    System.out.println("成功獲取鎖--------");
                    break;
                }
                Thread.sleep(sleepTime);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * @description 加鎖
     * 參數:jedis,k,v,過期時間
     * @date 15:05 2019/9/17
     **/
    public Boolean lock(Jedis jedis, String key, String value, Long timeOut) {
        // 保證原子性,同一時間只能一個key,並且不能被覆蓋:NX:如果存在不操作(返回null), EX:超時時間單位秒
        String result = jedis.set(key, value, "NX", "EX", timeOut);
        // 操作成功時返回"OK"
        return "OK".equals(result);
    }

    /**
     * @description 解鎖
     * 參數:jedis,k,v
     * @date 15:06 2019/9/17
     **/
    public static Boolean unLock(Jedis jedis, String key, String value) {
        // 如果k,v對存在 刪除,如果k,v不存在不刪除,(使用腳本可以保證操作的原子性)
        String luaScript = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then return redis.call(\"del\",KEYS[1]) else  return 0 end";
        Long result = (Long) jedis.eval(luaScript, Collections.singletonList(key), Collections.singletonList(value));
        return Long.valueOf(1).equals(result);
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章