網站首頁 編程語言 正文
需求背景
在開發的收入結轉平臺界面
上有一個歸集
按鈕,可以實現抓取結轉表里面的多條數據進行歸集操作。為了防止多人多電腦同時操作一條數據,我們自己開發了一個簡單的基于Redis實現的分布式鎖。
代碼實現
邏輯代碼中的使用案例
參數說明:
scIds
:結轉數據的ID主鍵集合。
timeOutToDeleteRedisKey
:最大鎖超時時間(用于自動解鎖)
organizationId
:租戶ID(這個參數根據情況選擇是否需要)
ReturnLock returnLock = RedisLock.applyByIds(scIds, redisLockTime, organizationId, () -> { // dothing 具體的代碼業務邏輯 return 123; }); if (!returnLock.getFlag()) { if(returnLock.getLock()){ throw new CommonException("歸集數據有程序正在運行,請稍候刷新頁面重試"); }else { throw new CommonException(returnLock.getErrorMsg()); } } // 返回對象 System.out.println(returnLock.getResObj()) // 123
Redis加鎖方法封裝
public static ReturnLock applyByIds(List<Long> scIds, Long timeOutToDeleteRedisKey, Long tenantId, Supplier<Object> supplier) { // 獲得鎖 Map<String, String> keyMap = getLockByIds(scIds, timeOutToDeleteRedisKey, tenantId); ReturnLock returnLock = new ReturnLock(); returnLock.setFlag(true); returnLock.setLock(false); try { // 判斷主鍵ID數量和加鎖的數量是否一致,不一致說明有加鎖失敗的數據,返回失敗鎖信息 if(scIds.size() > keyMap.size()){ returnLock.setFlag(false); returnLock.setLock(true); returnLock.setKeyMap(keyMap); return returnLock; } // 應用代碼執行后的返回結果 supplier:java8四大內置函數的供給型接口 // Supplier<T>(供給型接口)無參數,返回類型為T的對象:T get() returnLock.setResObj(supplier.get()); }catch (Exception e) { returnLock.setFlag(false); returnLock.setErrorMsg(e.getMessage()); e.printStackTrace(); }finally { // 應用代碼執行報錯,解鎖 unLockByIds(keyMap); } return returnLock; }
getLockByIds
批量獲取每一條數據的Redis鎖
private static Map<String, String> getLockByIds(List<Long> scIds, Long timeOutToDeleteRedisKey, Long tenantId) { Map<String, String> keyMap = new HashMap<>(); // 從spring上下文中獲取Redis的操作對象,因為這個代碼是寫在util中,所以通過上下文方式獲取bean對象 // RedisHelper:Redis的操作對象,我們自己公司基于redisTemplate封裝的 RedisHelper redisHelper = SpringUtil.getBean(RedisHelper.class); try { if (CollectionUtil.isNotEmpty(scIds)) { for (int i = 0; i < scIds.size(); i++) { String item = "L_" + scIds.get(i); String UUID = UUIDUtils.generateTenantUUID(tenantId); // 判斷key值是否被鎖,如果沒有鎖則加鎖并設置過期時間, 如果有鎖, 則報錯并立即釋放已加的鎖 // strSetIfAbsent會返回true/false,底層是封裝了java的setIfAbsent方法和Redis的setnx方法 // 如果設置成功返回true否則false if (redisHelper.strSetIfAbsent(item, UUID)) { // 設置過期時間 redisHelper.setExpire(item, timeOutToDeleteRedisKey, TimeUnit.SECONDS); // 保存設置的鎖信息 keyMap.put(item, UUID); } else { // 鎖設置異常,表示有數據被鎖住了,解鎖之間加鎖的數據 if (MapUtil.isNotEmpty(keyMap)) { if (unLockByIds(keyMap)) { // 解鎖失敗再次解鎖 unLockByIds(keyMap); } } // 返回鎖信息 return keyMap; } } } return keyMap; }catch (Exception e) { e.printStackTrace(); } }
解鎖
private static Boolean unLockByIds(Map<String, String> keyMap) { RedisHelper redisHelper = SpringUtil.getBean(RedisHelper.class); try { if (MapUtil.isEmpty(keyMap)) { return false; } // 判斷是否是自己的鎖 for (String key : keyMap.keySet()) { String uuid = keyMap.get(key); if (StringUtils.equals(uuid, redisHelper.strGet(key))) { // 封裝了redisTemplate.delete(key); redisHelper.delKey(key); } return true; }catch (Exception e) { e.printStackTrace(); return false; } }
實現效果
當對數據進行批量加鎖的時候,若在加鎖的過程中出現加鎖失敗,則回滾直接加的鎖,并提示"歸集數據有程序正在運行,請稍候刷新頁面重試"。
若業務代碼邏輯執行成功或者執行報錯都會自動的解鎖當前加鎖的數據。
原文鏈接:https://www.cnblogs.com/cqhcan/archive/2022/03/24/16048149.html
相關推薦
- 2022-05-06 CSRF攻擊是什么?如何防范CSRF攻擊?_安全相關
- 2023-03-30 Regex正則表達式判斷密碼強度_正則表達式
- 2022-12-26 詳解Golang中Context的原理和使用技巧_Golang
- 2023-07-26 vite中的glob-import批量導入
- 2022-06-17 go語言beego框架分頁器操作及接口頻率限制示例_Golang
- 2022-12-08 Python中的pandas庫簡介及其使用教程_python
- 2022-06-01 SQL為什么不建議執行超過3表以上的多表關聯查詢_MsSql
- 2022-08-28 詳解Python獲取線程返回值的三種方式_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支