redis分佈式鎖(樂觀鎖)

redis分佈式鎖:setNx自定義鎖

redis分佈式鎖原理:視頻教程:https://edu.csdn.net/course/play/25604

set命令:如果 key 已經持有其他值, SET 就覆寫舊值

setEX命令:成功返回ok,失敗返回no,如果 key 已經存在, SETEX 命令將覆寫舊值,可以設置有效時間

setNX命令:成功返回1,失敗返回0,若給定的 key 已經存在,則 SETNX 不做任何動做

 

流程

流程說明:

  • A、B線程同時通過setEX,setNX命令用同一個key去添加redis,由於redis是單線程的,只能有一個線程成功返回ok, A成功去處理業務邏輯,B失敗但是一直在循環添加redis
  • A執行業務邏輯完成後刪除redis的key,B就可以添加redis成功,去處理相應的業務邏輯
  • redis鎖一定要設置過期時間,防止A拿到鎖,當時還沒釋放程序中途出了異常,導致B一直拿不到鎖,程序卡死

 

自定義鎖代碼實現:(以下爲只用setNX實現方式)

  • lockkey可以是你的請求系統+請求流水等字段拼接的唯一的標識,過期時間比執行業務邏輯時間往上加一些就可以(一定要確保大於業務邏輯執行時間,否則A線程執行del時會因爲自己的鎖已經自動刪除,而去把B線程的鎖給刪掉)
  • 每個線程的key對應的value都不一樣,在刪除時可以根據value判斷是否是自己的redis,避免把其他線程的key刪除
  • 如果A線程做刪除操作時,通過value發現鎖是B線程的,這時A線程應該回滾並拋出異常,防止業務重複執行

業務代碼使用自定義鎖

// 生成redisKey:根據自己業務去拼接一個不唯一的字符串作爲Key
String lockKey = RedisKeyConstant.REDIS_SENTINEL_PREFIX + KeysGeneratorUtil.createRedisKey(
        InfoBO.getRequestSystem(), InfoBO.getEquityNo());
try {
    // 獲取鎖
    boolean lockResult = redisUtil.getLock(lockKey, 5000L);

    if (!lockResult) {
        log.error("獲取鎖失敗,redisKey:{}",lockKey);
        throw new EquityServiceException("錯誤碼");
    }
} catch (Exception e) {
    log.error("獲取鎖異常,redisKey:{}",lockKey);
    throw new ServiceException("錯誤碼");
}

// 加鎖成功,處理業務代碼

try {

   // 加鎖成功,處理業務代碼

} catch (Exception e ) {

   // 執行業務代碼異常

} finally {

   // 根據鎖Key釋放redis鎖:實際上是刪除的setNx中的key

  redisUtil.deleteKey(lockKey);

}

 

 

 

 

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