分佈式項目,由於用戶需要佔座需求,防止用戶同時進入該鏈接,導致事務失效,單獨使用事務的話,項目在兩臺服務器上面,導致事務實現不了這種鎖,因此添加上了redis單線程鎖。
具體實現流程 redis 工具類方法
// 鎖名稱
public static final String LOCK_PREFIX = "redis_lock";
// 加鎖失效時間,毫秒
public static final int LOCK_EXPIRE = 10000; // ms
/**
* 最終加強分佈式鎖
*
* @param key
* key值
* @return 是否獲取到
*/
public boolean lock(String key) {
String lock = LOCK_PREFIX + key;
// 利用lambda表達式
return (Boolean) redisTemplate.execute((RedisCallback) connection -> {
long expireAt = System.currentTimeMillis() + LOCK_EXPIRE + 1;
log.info("失效的時間是【{}】",String.valueOf(expireAt));
Boolean acquire = connection.setNX(lock.getBytes(), String.valueOf(expireAt).getBytes());
log.info("查看acquire========"+acquire);
if (acquire) {
return true;
} else {
byte[] value = connection.get(lock.getBytes());
log.info("查看value========"+value);
if (Objects.nonNull(value) && value.length > 0) {
long expireTime = Long.parseLong(new String(value));
log.info("查看expireTime========"+expireTime);
// 如果鎖已經過期
if (expireTime < System.currentTimeMillis()) {
log.info("如果鎖已經過期,重新加鎖");
// 重新加鎖,防止死鎖
byte[] oldValue = connection.getSet(lock.getBytes(),
String.valueOf(System.currentTimeMillis() + LOCK_EXPIRE + 1).getBytes());
log.info("查看oldValue========"+oldValue);
Boolean newLoing= Long.parseLong(new String(oldValue)) < System.currentTimeMillis();
log.info("查看Long.parseLong========"+newLoing);
return newLoing;
}
}
}
return false;
});
}
/**
* 刪除鎖
*
* @param key
*/
public void deleteLock(String key) {
redisTemplate.delete(key);
}
調用工具方法
@Override
public Boolean testRedis(String code) {
System.out.println("測試分佈式鎖的應用說明============查看鎖狀態"+redisManager.exists("redis_lockbbbbbbbbbb"));
Boolean flag=true;
System.out.println("測試分佈式鎖的應用說明============查看continue之後是否執行此日誌");
try {
while (true) {
if(redisManager.lock("bbbbbbbbbb")) {
Thread.sleep(5000);
code.substring(0, 2);
System.out.println("測試分佈式鎖的應用說明=============這是被鎖住的進程"+code);
System.out.println("測試分佈式鎖的應用說明=============查看是否進行下面邏輯"+code);
redisManager.deleteLock("redis_lockbbbbbbbbbb");
return true;
}else {
Thread.sleep(1000);
System.out.println("測試分佈式鎖的應用說明=============這是等待進行釋放鎖");
continue;
}
}
} catch (Exception e) {
System.out.println("測試分佈式鎖的應用說明=============拋出異常後發音日誌");
e.printStackTrace();
}
System.out.println("測試分佈式鎖的應用說明=============跳出循環後執行這個方法這是直接返回數據");
return false;
}
這是整個過程的使用,具體實現邏輯:
當用戶進入的時候,根據規則生成redis 的key ,同時添加過時時間,如果兩個人同時進入,那麼第一次進入的人的redis是開鎖狀態,第二個人進入的時候是閉鎖狀態, 因此第一個人會在serviceimpl中執行 Thread.sleep(5000);方法,相當於具體的邏輯,當邏輯執行完之後,將鎖釋放掉,第二個用戶會一直走下面的循環,直到鎖開了之後纔會進入具體的邏輯,
工具類中的邏輯 針對上鎖時間而言,並不是在超時之後就將redis 清空,工具的邏輯爲當超過過期時間之後,會再次給redis的key加鎖,這樣第二個請求就會進入,當然這樣的問題就是當第一個沒有執行完沒有自動釋放鎖的時候,鎖自動又加上了, 第二個請求會直接進入,因此枷鎖的時間需要想好,儘量在一個請求可以執行完的情況下的時間的幾倍。當然所有的邏輯中的要加上try catch 如果邏輯出錯,需要在catch中將鎖解開。大致就是這個意思!