日常在我們開發的過程中可能會用到編號的功能,如銷售訂單號,採購訂單號,紀錄檔編號,憑證號...等等,為了保證唯一有些表的主鍵要麼用自增長,要麼用GUID值,或通過雪花ID演演算法生成。這此方式基本都能產生唯一的ID,但如果在分散式環境下產生流水ID,以上這幾種方式可能就不太好用,如有以下場景
工作流的編號通常會是以下格式 如2022060200001-2022060299999 到了第二天時尾數又要生00001開始編,這種編號規則有一個好處就是非常直觀的通過工作流編號就可以看出來這是哪一天申請的流程,一天大概有多少流水碼。那麼如果我們用常規編號規則其實是比較難完成此需求的。
如在實際業務需求中 標準採購訂單要用5000000000-5999999999 這個號進行進行編碼,委外採購訂單用4000000000-4999999999號段進行編碼
在辦裡某業務時根據業務型別使用不同的編號 如財務收款用的流水號是 SK10000000-SK99999999,支出用的是ZC10000000-ZC99999999
根據以上的業務場景如果使用常規的編號是比較難實現的(要保證分散式環境編號不重複且按流水編碼),那麼HiSql
提供了比較方便的解決方案
該版本還未正式更新nuget 需要使用請下載原始碼
//如果需要使用編號那麼一定要開啟此功能
HiSql.Global.SnroOn = true;
//開啟編號後進行初始化
sqlClient.CodeFirst.InstallHisql();//僅需執行一次 如果使用的低版本的HiSql 升級參照包手需要重新初始化安裝
初始安裝完成後會生成表Hi_Snro
這個編號設定表
Hi_Snro
表詳細說明
欄位 | 描述 | 備註 |
---|---|---|
SNRO |
編號規則名稱 | 主鍵 字串(10) |
SNUM |
子編號 | 主鍵 整數 |
IsSnow |
是否雪花ID | bool true:表示雪花id false:表示自定義流水編號 |
SnowTick |
雪花ID時間戳 | int64 IsSnow 為true時設定 大於0 都可以,其它的都可以不用設定 |
StartNum |
編號開始值 | 字串(20) 當IsNumber 為true 時編號只能純數位 為false時 可以以0-9 A-Z 混編 |
EndNum |
編號結束值 | 字串(20) 當編號超過此時時將會丟擲異常號段池已滿 |
CurrNum |
當前編號值 | 字串(20) 第一次設定時值要等於StartNum |
CurrAllNum |
當前完整編號 | 字串(40) 不需要設定,產生流水時會自動生成 |
Length |
編號長度 | StartNum 和EndNum 的長度 兩者的長度要一至否則會報錯 |
IsNumber |
是否純數位編號 | 當為true 編號按0-9的10進位制數位編號,當為false時按0-9 A-Z 36進度數位和字母混合編號 |
IsHasPre |
是否有前輟 | 可以按到年月日時分秒作為前輟 在PreType 設定 |
PreType |
前輟編號型別 | 詳細請見 PreType 前置編號型別設定 |
FixPreChar |
固定前輟 | 固定一個字串 每個生成的碼前面都加上這個值 |
PreChar |
當前前輟 | 不需要設定 在編號的過程中會將 FixPreChar 和 PreType 存在此昝 |
CacheSpace |
號段快取 | 編號使用越頻繁這個值設定越大 常的建議設定為10 值越大編號效能越好 |
CurrCacheSpace |
當前快取池使用的數量 | 不需要設定 |
Descript |
編號描述 | 備註一下當前編號規則 |
PreType
前置編號型別設定在PreType
是一個列舉類
欄位 | 值 | 備註 |
---|---|---|
PreType.None |
0 | 表示無前置 |
PreType.Y |
1 | 表示前置為日期格式[yyyy] 即當前年份如2022 |
PreType.Y2 |
12 | 表示前置為日期格式[yy] 即當前年份後兩位如22 |
PreType.YM |
2 | 表示前置為日期格式[yyyyMM] 即當前年月如202206 |
PreType.Y2M |
22 | 表示前置為日期格式[yyMM] 即當前年月如2206 |
PreType.YMD |
3 | 表示前置為日期格式[yyyyMMdd] 即當前年月日如20220602 |
PreType.Y2MD |
32 | 表示前置為日期格式[yyMMdd] 即當前年月日如220602 |
PreType.YMDH |
4 | 表示前置為日期格式[yyyyMMddHH] 即當前年月日時如2022060216 |
PreType.Y2MDH |
42 | 表示前置為日期格式[yyMMddHH] 即當前年月日時如22060216 |
PreType.YMDHm |
5 | 表示前置為日期格式[yyyyMMddHHmm] 即當前年月日時分如202206021630 |
PreType.Y2MDHm |
52 | 表示前置為日期格式[yyMMddHHmm] 即當前年月日時分如2206021630 |
PreType.YMDHms |
6 | 表示前置為日期格式[yyyyMMddHHmmss] 即當前年月日時分秒如20220602163020 |
PreType.Y2MDHms |
62 | 表示前置為日期格式[yyMMddHHmmss] 即當前年月日時分秒如220602163020 |
根據以上設定規則將資料設定到表中
Hi_Snro
的設定可以自行做個設定介面進行設定,以下是通過程式進行設定儲存.
List<Hi_Snro> list = new List<Hi_Snro>();
///工作流編號設定
///按天產生流水號 如2205061000000-2205069999999 之間
list.Add( new Hi_Snro { SNRO = "WFNO", SNUM = 1, IsSnow = false, SnowTick = 0, StartNum = "1000000", EndNum = "9999999", Length = 7, CurrNum = "1000000", IsNumber = true, PreType=PreType.Y2MD, FixPreChar="", IsHasPre = true, CacheSpace = 5, Descript = "工作流編號" });
///生成銷售訂單編碼 每分鐘從0開始編號 如20220602145800001-20220602145899999
list.Add(new Hi_Snro{ SNRO = "SALENO", SNUM = 1, IsSnow = false, SnowTick = 0, StartNum = "10000", EndNum = "99999", Length = 5, CurrNum = "10000", IsNumber = true, PreType = PreType.YMDHm, FixPreChar = "", IsHasPre = true, CacheSpace = 10, Descript = "銷售訂單號流水" });
///生成另外一種銷售訂單編碼 年的是取後兩位 按每秒順序生成 如22060214581200001-22060214581299999
list.Add(new Hi_Snro { SNRO = "SALENO", SNUM = 2, IsSnow = false, SnowTick = 0, StartNum = "10000", EndNum = "99999", Length = 5, CurrNum = "10000", IsNumber = true, PreType = PreType.Y2MDHms, FixPreChar = "", IsHasPre = true, CacheSpace = 10, Descript = "銷售訂單號流水" });
///通過雪花ID生成
list.Add( new Hi_Snro { SNRO = "Order", SNUM = 1, IsSnow=true, SnowTick=145444, StartNum = "", EndNum = "",Length=7, CurrNum = "", IsNumber = true, IsHasPre = false, CacheSpace = 10, Descript = "訂單號雪花ID" });
//儲存設定到表中
sqlClient.Modi("Hi_Snro", list).ExecCommand();
建議把SeriNumber 做成一個局靜態變數
public static SeriNumber number = null; //定義個全域性變更的流水號物件
設定連線
//sqlClient 為資料庫連線物件
number = new SeriNumber(sqlClient);
如果應用進行了分散式佈署 請一定要啟用以下程式碼
HiSql.Global.RedisOn = true;//開啟redis快取
HiSql.Global.RedisOptions = new RedisOptions { Host = "172.16.80.178", PassWord = "qwe123", Port = 6379, CacheRegion = "HRM", Database = 2 };
HiSql.Global.NumberOptions.MultiMode= true;
//如果部署了分散式且也要生成雪花ID 一定要設定以下當前應用的ID 多個應用間只要不重複即可0-31之間
HiSql.Global.NumberOptions.WorkId=1;
通過以上設定則分散式編號環境設定完成,下面就可以進行編號測試了
為了測試編號是否有重複我這裡建了一個測試記錄表H_nlog
,編號生成完成後可以分析該表的資料看是否有重複資料,(測試環境 為SqlServer
) sql程式碼如下
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[H_nlog](
[Nid] [int] IDENTITY(1,1) NOT NULL,
[Numbers] [varchar](50) NULL,
[CreateTime] [datetime] NULL,
[CreateName] [nvarchar](50) NULL,
[ModiTime] [datetime] NULL,
[ModiName] [nvarchar](50) NULL,
CONSTRAINT [PK_H_nlog] PRIMARY KEY CLUSTERED
(
[Nid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[H_nlog] ADD CONSTRAINT [DF_H_nlog_CreateTime] DEFAULT (getdate()) FOR [CreateTime]
GO
ALTER TABLE [dbo].[H_nlog] ADD CONSTRAINT [DF_H_nlog_CreateName] DEFAULT ('') FOR [CreateName]
GO
ALTER TABLE [dbo].[H_nlog] ADD CONSTRAINT [DF_H_nlog_ModiTime] DEFAULT (getdate()) FOR [ModiTime]
GO
ALTER TABLE [dbo].[H_nlog] ADD CONSTRAINT [DF_H_nlog_ModiName] DEFAULT ('') FOR [ModiName]
GO
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'建立時間' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_nlog', @level2type=N'COLUMN',@level2name=N'CreateTime'
GO
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'建立人' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_nlog', @level2type=N'COLUMN',@level2name=N'CreateName'
GO
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'修改時間' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_nlog', @level2type=N'COLUMN',@level2name=N'ModiTime'
GO
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'修改人' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_nlog', @level2type=N'COLUMN',@level2name=N'ModiName'
GO
根據編號規則WFNO
子編號1
生成編號
List<object> lst = new List<object>();
for (int i = 0; i < 1000; i++)
{
var num = number.NewNumber("WFNO", 1);
lst.Add(new { Numbers = num });
Console.WriteLine(num);
}
sqlClient.Insert("H_nlog", lst).ExecCommand();
測試結果
啟用了分散式多個應用同時對同一個編號規則產生編號不會產生重複編號。