日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

dotNET Core实现分布式环境下的流水号唯一

發布時間:2023/12/4 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 dotNET Core实现分布式环境下的流水号唯一 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

業務背景

在管理系統中,很多功能模塊都會涉及到各種類型的編號,例如:流程編號、訂單號、合同編號等等。編號各有各自的規則,但通常有一個流水號來確定編號的唯一性,保證流水號的唯一,在不同的環境中實現方式有所不同。本文將介紹在單機和分布式環境中保證流水號唯一的方式。

實現思路

1、在數據庫中創建 seqno 表,每個業務一條數據,存儲業務 code 和流水號的最大值

環境

  • dotNET Core:2.1

  • VS For Mac:2019

  • Docker:18.09.2

  • MySql:8.0.17,基于Docker構建

  • Redis:3.2,基于Docker構建

  • CSRedisCore:3.1.5

準備工作

1、執行下面命令構建 Redis 容器

docker?run?-p?6379:6379??-d?--name?s2redis_test???--restart=always?redis:3.2???redis-server?--appendonly?yes

2、執行下面命令構建 MySql 容器

docker?run?-d?-p?3306:3306?-e?MYSQL_USER="oec2003"?-e?MYSQL_PASSWORD="123456"?-e?MYSQL_ROOT_PASSWORD="123456"?--name?s2mysql?mysql/mysql-server?--character-set-server=utf8mb4?--collation-server=utf8mb4_general_ci?--default-authentication-plugin=mysql_native_password

3、在 MySql 中創建數據庫seqno_test,執行下面 SQL 創建表和測試數據

--?---------------------------- --?Table?structure?for?seqno --?---------------------------- DROP?TABLE?IF?EXISTS?`seqno`; CREATE?TABLE?`seqno`?(`code`?varchar(50)?COLLATE?utf8mb4_general_ci?DEFAULT?NULL,`num`?int(11)?DEFAULT?NULL )?ENGINE=InnoDB?DEFAULT?CHARSET=utf8mb4?COLLATE=utf8mb4_general_ci;--?---------------------------- --?Records?of?seqno --?---------------------------- BEGIN; INSERT?INTO?`seqno`?VALUES?('order',?1); COMMIT;SET?FOREIGN_KEY_CHECKS?=?1;

4、在 VS2019 中創建兩個控制臺項目和一個類庫項目,如下圖:

單機測試

1、在 SeqNo 類中添加 GetSeqByNoLock 方法

public?static?string?GetSeqNoByNoLock() {string?connectionStr?=?"server?=?localhost;?user?id?=?oec2003;?password?=?123456;?database?=?seqno_test";string?getSeqNosql?=?"select?num?from?seqno?where?code='order'";string?updateSeqNoSql?=?"update?seqno?set?num=num+1?where?code='order'";var?seqNo?=?MySQLHelper.ExecuteScalar(connectionStr,?System.Data.CommandType.Text,?getSeqNosql);MySQLHelper.ExecuteNonQuery(connectionStr,?System.Data.CommandType.Text,?updateSeqNoSql);return?seqNo.ToString(); }

2、在 RedisLockConsoleApp1 控制臺程序中用多線程來模擬測試

class?Program {static?void?Main(string[]?args){Task.Run(()?=>{for?(int?i?=?0;?i?<?50;?i++){Console.WriteLine($"Thread1:SeqNo:{SeqNo.GetSeqNoByNoLock()}");}});Task.Run(()?=>{for?(int?i?=?0;?i?<?50;?i++){Console.WriteLine($"Thread2:SeqNo:{SeqNo.GetSeqNoByNoLock()}");}});Console.ReadLine();} }

3、測試結果如下,可以看出在多線程情況下會出現重復的編號

單機環境加鎖測試

在 SeqNo 類中添加 GetSeqNoByLock 方法,通過 Monitor.Enter 來解決單機多線程流水號重復問題

public?static?string?GetSeqNoByLock() {string?connectionStr?=?"server?=?localhost;?user?id?=?oec2003;?password?=?123456;?database?=?seqno_test";string?getSeqNosql?=?"select?num?from?seqno?where?code='order'";string?updateSeqNoSql?=?"update?seqno?set?num=num+1?where?code='order'";var?seqNo?=?string.Empty;try{Monitor.Enter(_myLock);seqNo?=?MySQLHelper.ExecuteScalar(connectionStr,?System.Data.CommandType.Text,?getSeqNosql).ToString();MySQLHelper.ExecuteNonQuery(connectionStr,?System.Data.CommandType.Text,?updateSeqNoSql);Monitor.Exit(_myLock);}catch{Monitor.Exit(_myLock);}return?seqNo.ToString(); }

運行結果如下,可以看出已經沒有出現重復的流水號了

多機環境測試

Monitor 只能解決進程內的重復性問題,現在用兩個控制臺程序來模擬分布式下的多機器運行,在 RedisLockConsoleApp2 控制臺程序添加如下代碼

static?void?Main(string[]?args) {Task.Run(()?=>{for?(int?i?=?0;?i?<?50;?i++){Console.WriteLine($"Thread1:SeqNo:{SeqNo.GetSeqNoByLock()}");}});Task.Run(()?=>{for?(int?i?=?0;?i?<?50;?i++){Console.WriteLine($"Thread2:SeqNo:{SeqNo.GetSeqNoByLock()}");}});Console.ReadLine(); }

同時運行兩個控制臺程序,測試結果如下:

可以看出在每一個控制臺程序內沒有重復流水號,但兩個控制臺還是會間歇性地出現重復流水號。

要解決這個問題就必須使用分布式鎖。

多機環境分布式鎖測試

分布式鎖又很多實現方式,本例中采用 Redis 來實現,Redis 客戶端使用的是 CSRedisCore ,在 CSRedisCore 最新的版本 3.1.5 中實現了分布式鎖,這讓使用變得非常的方便。

1、在 RedisLockLib 項目中添加 CSRedisCore 包的引用

2、在 SeqNo 類中添加 GetSeqNoByRedisLock 方法

public?static?string?GetSeqNoByRedisLock() {string?connectionStr?=?"server?=?localhost;?user?id?=?oec2003;?password?=?123456;?database?=?seqno_test";string?getSeqNosql?=?"select?num?from?seqno?where?code='order'";string?updateSeqNoSql?=?"update?seqno?set?num=num+1?where?code='order'";var?seqNo=string.Empty;using?(_redisClient.Lock("test",?5000)){seqNo?=?MySQLHelper.ExecuteScalar(connectionStr,?System.Data.CommandType.Text,?getSeqNosql).ToString();MySQLHelper.ExecuteNonQuery(connectionStr,?System.Data.CommandType.Text,?updateSeqNoSql);}return?seqNo; }

3、測試結果如下:

總結

例子非常簡單,提供一種解決問題的思路,如您有更好的方式歡迎討論。本文的示例代碼已上傳 Github ,地址如下:

https://github.com/oec2003/StudySamples/tree/master/RedisLockDemo

祝大家假期快樂!

總結

以上是生活随笔為你收集整理的dotNET Core实现分布式环境下的流水号唯一的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。