package com.example.demo.redis;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import java.util.Collections;
/**
* @Author Xiao HE
* @Create Time 2019/9/2 16:33
**/
@Component
public class RedisTool {
//Redis 執行成功返回
private static final String LOCK_SUCCESS = "OK";
// NX是不存在時才set, XX是存在時才set, EX是秒,PX是毫秒
private static final String SET_IF_NOT_EXIST = "NX";
// 設置 過期時間類型 EX = 秒 PX = 毫秒
private static final String SET_WITH_EXPIRE_TIME = "EX";
/**
* 嘗試獲取分佈式鎖
* @param jedis Redis客戶端
* @param lockKey 鎖
* @param requestId 請求標識
* @param expireTime 超期時間
* @return 是否獲取成功
*/
public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
if (LOCK_SUCCESS.equals(result)) {
return true;
}
return false;
}
private static final Long RELEASE_SUCCESS = 1L;
/**
* 釋放分佈式鎖
* @param jedis Redis客戶端
* @param lockKey 鎖
* @param requestId 請求標識
* @return 是否釋放成功
*/
public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
if (RELEASE_SUCCESS.equals(result)) {
return true;
}
return false;
}
}
package com.example.demo.MyTest;
import com.example.demo.redis.RedisTool;
import com.example.demo.service.UserService;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import lombok.Data;
import org.apache.logging.log4j.util.Strings;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import redis.clients.jedis.Jedis;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import static redis.clients.jedis.Protocol.Command.EXPIRE;
/**
* @Author Xiao HE
* @Create Time 2019/8/30 21:41
**/
@SpringBootTest
@RunWith(SpringRunner.class)
public class MyTest2 {
@Value("${spring.redis.host}")
public static String host;
static boolean isOpenExpirationRenewal = true;
public static void main(String[] args) throws Exception{
Jedis jedis = new Jedis(host);
String lockKey = "zhendifan";
String lockValue = UUID.randomUUID().toString();
//設置過期時間未 120 秒
boolean redisBoolean = RedisTool.tryGetDistributedLock(jedis, lockKey, lockValue, 120);
if(redisBoolean){
System.out.println("拿到redis 鎖 進入方法");
Thread thread = new Thread(new ExpirationRenewal(jedis, lockKey, lockValue));
thread.start(); //啓動線程
try{
System.out.println("邏輯代碼執行中.........");
//假設需要執行兩分鐘
Thread.sleep(120000);
}catch (Exception e){
throw new Exception("發生異常!異常信息"+e);
}finally {
// 關閉線程
isOpenExpirationRenewal=false;
thread.interrupt();
//釋放Redis 鎖
RedisTool.releaseDistributedLock(jedis,lockKey,lockValue);
}
}
}
/*
* 刷新Key 過期時間 保證業務處理時間大於過期時間
* @param jedis Redis客戶端
* @@param lockKey 鎖
* @param requestId 請求標識
* */
@Data
public static class ExpirationRenewal implements Runnable{
private Jedis jedis;
private String lockKey;
private String lockValue;
public ExpirationRenewal(Jedis jedis, String lockKey, String lockValue) {
this.jedis = jedis;
this.lockKey = lockKey;
this.lockValue = lockValue;
}
@Override
public void run(){
//監測 鎖過期時間
while (isOpenExpirationRenewal){
System.out.println("執行延遲失效時間中...");
String checkAndExpireScript = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
"return redis.call('expire',KEYS[1],ARGV[2]) " +
"else " +
"return 0 end";
// 鎖過期後重新給鎖設置過期時間 15 秒
jedis.eval(checkAndExpireScript, 1, this.lockKey, this.lockValue, "15");
//如果不行 就直接Set 去重新設置過期時間
try {
//休眠10秒
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}