分布式鎖實現方案 - Lock4j 使用

一、Lock4j 分布式鎖工具

你是不是在使用分布式鎖的時候,還在自己用 AOP 封裝框架?那么 Lock4j 你可以考慮一下。

Lock4j 是一個分布式鎖組件,其提供了多種不同的支持以滿足不同性能和環境的需求。

立志打造一個簡單但富有內涵的分布式鎖組件。

并且支持redission,redisTemplate,zookeeper。可混用,支持擴展。

Giee地址:https://gitee.com/baomidou/lock4j

二、使用方式

這里我以 redisson 作為分布式鎖的底層。

添加依賴:

<dependency><groupId>com.baomidou</groupId><artifactId>lock4j-redisson-spring-boot-starter</artifactId><version>2.2.5</version>
</dependency>

然后再配置中增加 redis 的配置:

spring:redis:timeout: 6000password:cluster:max-redirects:nodes:- 192.168.40.120:6379- 192.168.40.121:6379- 192.168.40.122:6379

聲明 RedissonClient

@Configuration
public class RedissonConfig {@Beanpublic RedissonClient getRedisson(RedisProperties redisProperties) {Config config = new Config();String[] nodes = redisProperties.getCluster().getNodes().stream().filter(StringUtils::isNotBlank).map(node -> "redis://" + node).collect(Collectors.toList()).toArray(new String[]{});ClusterServersConfig clusterServersConfig = config.useClusterServers().addNodeAddress(nodes);if (StringUtils.isNotBlank(redisProperties.getPassword())) {clusterServersConfig.setPassword(redisProperties.getPassword());}clusterServersConfig.setConnectTimeout((int) (redisProperties.getTimeout().getSeconds() * 1000));clusterServersConfig.setScanInterval(2000);return Redisson.create(config);}
}

然后只需在需要分布式鎖的地方加 @Lock4j 即可:

@RestController
@RequestMapping("/lock")
public class Lock4jController {//不指定,默認獲取鎖超時3秒,30秒鎖過期@Lock4j@GetMapping("/test")public String test() {return "success";}@Lock4j(keys = {"#id", "#name"}, expire = 60000, acquireTimeout = 10000)@GetMapping("/test1")public String test1(Long id, String name) {Thread.sleep(5000);return "success";}}

如果同時兩次訪問 /test1,可以感覺出第二次沒有獲得鎖的請求等待的時間更長,因為要等待鎖的釋放:

在這里插入圖片描述

獲取鎖超時時間和鎖過期時間,可以通過配置在配置文件中全局生效:

lock4j:acquire-timeout: 3000 #默認值3s,可不設置expire: 30000 #默認值30s,可不設置primary-executor: com.baomidou.lock.executor.RedisTemplateLockExecutor #默認redisson>redisTemplate>zookeeper,可不設置lock-key-prefix: lock4j #鎖key前綴, 默認值lock4j,可不設置

acquire-timeout 等待鎖的時長,超過這個時間會默認拋出 com.baomidou.lock.exception.LockFailureException 異常。

在這里插入圖片描述

也可以自定義異常捕獲,需要實現 LockFailureStrategy 接口:

@Slf4j
@Component
public class MyLockFailureStrategy implements LockFailureStrategy {@Overridepublic void onLockFailure(String key, Method method, Object[] arguments) {log.error("key: {} , method: {} ,arguments: {} ", key, method.getName(), Arrays.asList(arguments).toString());}
}

如果獲取鎖超時,則可以看到打印的日志:

在這里插入圖片描述

鎖的獲取邏輯也可以自定義,如果是 Redisson 依賴下,可以繼承 AbstractLockExecutor<RLock> 抽象類,例如:

@Slf4j
@Component
public class MyLockExecutor extends AbstractLockExecutor<RLock> {@ResourceRedissonClient redissonClient;/*** 嘗試獲取鎖*/@Overridepublic RLock acquire(String lockKey, String lockValue, long expire, long acquireTimeout) {log.info("key: {} 嘗試獲取鎖", lockKey);try {RLock lockInstance = this.redissonClient.getLock(lockKey);boolean locked = lockInstance.tryLock(acquireTimeout, expire, TimeUnit.MILLISECONDS);return (RLock)this.obtainLockInstance(locked, lockInstance);} catch (InterruptedException var9) {return null;}}/*** 釋放鎖*/@Overridepublic boolean releaseLock(String key, String value, RLock lockInstance) {log.info("key: {} 釋放鎖", key);if (lockInstance.isHeldByCurrentThread()) {try {return (Boolean)lockInstance.forceUnlockAsync().get();} catch (InterruptedException | ExecutionException var5) {return false;}} else {return false;}}
}

然后在使用時指定執行器:

@Lock4j(keys = {"#id", "#name"}, expire = 60000, acquireTimeout = 1000, executor = MyLockExecutor.class)
@GetMapping("/test2")
public String test2(Long id, String name) throws InterruptedException {Thread.sleep(5000);return "success";
}

請求 test2 接口可以看到打印的日志:

在這里插入圖片描述

Key 的生成也可以自定義,只需繼承 DefaultLockKeyBuilder 抽象類,例如:

@Slf4j
@Component
public class MyLockKeyBuilder extends DefaultLockKeyBuilder {public MyLockKeyBuilder(BeanFactory beanFactory) {super(beanFactory);}@Overridepublic String buildKey(MethodInvocation invocation, String[] definitionKeys) {String key = super.buildKey(invocation, definitionKeys);log.info("生成的key:{} ", key);return key;}
}

運行后可以觀察日志:

在這里插入圖片描述

上面都是通過注解的方式,同樣也可以手動控制鎖的獲取和釋放,只需要引入 LockTemplate ,例如:

@RestController
@RequestMapping("/lock")
public class Lock4j2Controller {@Resourceprivate LockTemplate lockTemplate;@GetMapping("/test3")public String test1(Long id, String name) {// 獲取鎖final LockInfo lockInfo = lockTemplate.lock(id + name, 30000L, 5000L, RedissonLockExecutor.class);try {Thread.sleep(5000);return "success";} catch (InterruptedException e) {throw new RuntimeException(e);} finally {//釋放鎖lockTemplate.releaseLock(lockInfo);}}
}

三、通過鎖實現限流

在注解中 autoRelease 控制著是否自動在方法執行結束后釋放鎖,如果為 false 則是在 expire 時間到的時候移除鎖,實際是通過 Redis 的過期機制,通過這個機制可以限制某個 key 的訪問頻次,例如:

@Lock4j(keys = {"#id", "#name"}, expire = 3000, acquireTimeout = 10000, autoRelease = false)
@GetMapping("/test4")
public String test4(Long id, String name) throws InterruptedException {return "success";
}

當同一個 idname 第一次訪問的時候速度會很快:

在這里插入圖片描述

如果頻繁訪問則會被限流:

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/214055.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/214055.shtml
英文地址,請注明出處:http://en.pswp.cn/news/214055.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Redis分布式緩存超詳細總結!

文章目錄 前言一、Redis持久化解決數據丟失問題1.RDB&#xff08;Redis Database Backup file&#xff09;持久化&#xff08;1&#xff09;執行RDB&#xff08;2&#xff09;RDB方式bgsave的基本流程&#xff08;3&#xff09;RDB會在什么時候執行&#xff1f;save 60 1000代表…

VBA信息獲取與處理:在EXCEL中隨機函數的利用

《VBA信息獲取與處理》教程(版權10178984)是我推出第六套教程&#xff0c;目前已經是第一版修訂了。這套教程定位于最高級&#xff0c;是學完初級&#xff0c;中級后的教程。這部教程給大家講解的內容有&#xff1a;跨應用程序信息獲得、隨機信息的利用、電子郵件的發送、VBA互…

RabbitMQ學習

一、RabbitMQ 采用 AMQP 高級消息隊列協議的一種消息隊列技術,最大的特點就是消費并不需要確保提供方存在,實現了服務之間的高度解耦 1、在分布式系統下具備異步,削峰,負載均衡等一系列高級功能; 2、擁有持久化的機制&#xff0c;進程消息&#xff0c;隊列中的信息也可以保存下…

計算機網絡(三) | 數據鏈路層 PPP協議、廣播CSMA/CD協議、集線器、交換器、擴展and高速以太網

文章目錄 1 數據鏈路基本概念和問題1.1 基本概念1.2 基本問題&#xff08;1&#xff09;封裝成幀&#xff08;2&#xff09;透明傳輸&#xff08;3&#xff09;差錯控制 2.數據鏈路層協議2.1 點對點 PPP協議2.1.1 需要實現的2.1.2 PPP組成2.1.3 幀格式2.1.4 工作流程 2.2 廣播 …

內網穿透的應用-如何結合Cpolar內網穿透工具實現在IDEA中遠程訪問家里或者公司的數據庫

文章目錄 1. 本地連接測試2. Windows安裝Cpolar3. 配置Mysql公網地址4. IDEA遠程連接Mysql小結 5. 固定連接公網地址6. 固定地址連接測試 IDEA作為Java開發最主力的工具&#xff0c;在開發過程中需要經常用到數據庫&#xff0c;如Mysql數據庫&#xff0c;但是在IDEA中只能連接本…

配置BFD多跳檢測示例

BFD簡介 定義 雙向轉發檢測BFD&#xff08;Bidirectional Forwarding Detection&#xff09;是一種全網統一的檢測機制&#xff0c;用于快速檢測、監控網絡中鏈路或者IP路由的轉發連通狀況。 目的 為了減小設備故障對業務的影響&#xff0c;提高網絡的可靠性&#xff0c;網…

“==”和“equals”的區別

“”和“equals”的區別 Java中“”和“equals”的區別在于&#xff0c;它們比較的內容不同。""比較的是對象的引用是否相等&#xff0c;而equals比較的是對象的值是否相等。 具體來說&#xff0c;以下是兩個操作符之間的區別&#xff1a; “”比較的是對象的引用&…

【鏈表Linked List】力扣-117 填充每個節點的下一個右側節點指針II

目錄 問題描述 解題過程 官方題解 問題描述 給定一個二叉樹&#xff1a; struct Node {int val;Node *left;Node *right;Node *next; } 填充它的每個 next 指針&#xff0c;讓這個指針指向其下一個右側節點。如果找不到下一個右側節點&#xff0c;則將 next 指針設置為 N…

C++中字符串詳解

在C語言中只能通過字符串數組來模擬字符串&#xff0c;沒有字符串類型。在C引入了string類來表示字符串類型。從而用它定義字符串。 在C語言中&#xff1a; char str[] "abc"; char str[] {a&#xff0c;b,c,\0}; char* str "abc"; //這三種形式是C語言…

因為高考考砸了,我學了計算機

2015年&#xff0c;是我高中的最后一年。 2023年&#xff0c;我已在計算機領域工作十多個年頭。 我出生在東部省份的一個不沿海小縣城&#xff0c;在那里度過了我高考前的17年。起點平平&#xff0c;沒有任何特長傍身&#xff0c;也可以說是毫無亮點&#xff1b;成績中等&#…

代碼隨想錄算法訓練營第四十五天 _ 動態規劃_ 70. 爬樓梯、322.零錢兌換、279.完全平方數、139.單詞拆分。

學習目標&#xff1a; 動態規劃五部曲&#xff1a; ① 確定dp[i]的含義 ② 求遞推公式 ③ dp數組如何初始化 ④ 確定遍歷順序 ⑤ 打印遞歸數組 ---- 調試 引用自代碼隨想錄&#xff01; 60天訓練營打卡計劃&#xff01; 學習內容&#xff1a; 70. 爬樓梯 動態規劃五步曲&…

中文語音標注工具FunASR(語音識別)

全稱 A Fundamental End-to-End Speech Recognition Toolkit&#xff08;一個語音識別工具&#xff09; 可能大家用過whisper&#xff08;openAi&#xff09;&#xff0c;它【標注英語的確很完美】&#xff0c;【但中文會出現標注錯誤】或搞了個沒說的詞替換上去&#xff0c;所…

【Fiddler】IDEA配置Fiddler

由于遇上了個迷之請求&#xff0c;接口調用正常&#xff0c;OkHttpClient調用正常&#xff0c;RestTemplate調用失敗&#xff0c;所以想看看發送的報文是怎樣的&#xff0c;所以就下了個Fiddler 問題 下載安裝&#xff0c;以及如何安裝證書&#xff0c;網上太多相同文章了&…

APP備案,最新獲取安卓簽名文件中MD5等信息方法

1.通過簽名文件獲取SHA1和SHA256 直接通過cmd執行命令 keytool -list -v -keystore xxxxx/xxx/xx/xxx.keystore輸入后回車會提示輸入密碼庫口令&#xff0c;直接輸入Keystore密碼&#xff08;輸入過程中終端上不會顯示&#xff0c;輸完回車就行&#xff09; 2.獲取md5 由于…

redis集群(cluster)筆記

1. 定義&#xff1a; 由于數據量過大&#xff0c;單個Master復制集難以承擔&#xff0c;因此需要對多個復制集進行集群&#xff0c;形成水平擴展每個復制集只負責存儲整個數據集的一部分&#xff0c;這就是Redis的集群&#xff0c;其作用是提供在多個Redis節點間共享數據的程序…

IDEA啟動失敗報錯解決思路

IDEA啟動失敗報錯解決思路 背景&#xff1a;在IDEA里安裝插件失敗&#xff0c;重啟后直接進不去了&#xff0c;然后分析問題解決問題的過程記錄下來。方便下次遇到快速解決。也是一種解決問題的思路&#xff0c;分享出去。 啟動報錯信息 Internal error. Please refer to https…

加索引后 sql loader-951

加索引后 sql loader-951 現象解決過程最終解決 現象 之前使用sqlldr正常&#xff0c;加表索引后使用sqlldr時 報錯 SQL Loader-951 解決過程 百度&#xff0c;說可能是鎖表&#xff08;或者表未提交&#xff09; 查看沒有對應未commit數據&#xff0c;且沒有鎖表。查看對應…

【筆記 Python 01】基本數據類型、基本類型

文章目錄 類型是否可轉換基本類型匯總集合 set【創建】【添加元素】【刪除】【清空】【差集】【交集】【并集】【update 批量更新】【set → numpy】 元組 tuple ()【描述】【優點】【元組的創建】【元組的插入】【刪除元組】 字典 dict {}【創建空列表】【創建列表】【字典的獲…

ke14--10章-1數據庫JDBC介紹

注冊數據庫(兩種方式),獲取連接,通過Connection對象獲取Statement對象,使用Statement執行SQL語句。操作ResultSet結果集 ,回收數據庫資源. 需要語句: 1Class.forName("DriverName");2Connection conn DriverManager.getConnection(String url, String user, String…

抖音各加密參數說明和獲取(含代碼)

?X-Bogus&#xff1a;X-Bogus是一種防數據包偽造的一個參數&#xff0c; 又稱為x偽造&#xff0c;主要用于反爬蟲&#xff0c;這個是某節公司下面基礎服務&#xff0c;這個反爬蟲機制幾乎用在了它所有的產品中&#xff0c;不過&#xff0c;只要是能正常使用&#xff0c;這些東…