在一些系統(tǒng)中,經(jīng)理要生成單據(jù)號,為了不使多臺客戶端生成的單據(jù)號重復(fù),一般要在服務(wù)端生成這種流水號,本文是在數(shù)據(jù)庫中生成流水號,并且可以生成多種類型的單據(jù)號(比如銷售單據(jù)號,盤點單據(jù)號,進(jìn)貨單據(jù)號等),利用數(shù)據(jù)庫鎖的原理,先看一下SQL語句:
成都創(chuàng)新互聯(lián)專注于企業(yè)全網(wǎng)整合營銷推廣、網(wǎng)站重做改版、蓬溪網(wǎng)站定制設(shè)計、自適應(yīng)品牌網(wǎng)站建設(shè)、html5、商城網(wǎng)站建設(shè)、集團(tuán)公司官網(wǎng)建設(shè)、成都外貿(mào)網(wǎng)站建設(shè)公司、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計等建站業(yè)務(wù),價格優(yōu)惠性價比高,為蓬溪等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。CREATE TABLE [dbo].[Lshs]( [MAXLSH] [BIGINT] NULL, [LSHDate] [DATETIME] NULL, [LX] [NVARCHAR](6) NULL ) ON [PRIMARY]
CREATE PROC [dbo].[getlsh] @lx VARCHAR(6) , @lsh VARCHAR(30) OUTPUT AS BEGIN --啟動事務(wù)處理 DECLARE@tran_point INT --控制事務(wù)嵌套 SET @tran_point = @@trancount --保存事務(wù)點 IF @tran_point = 0 BEGINTRAN tran_SOF_getmaxdjbh ELSE SAVETRAN tran_SOF_getmaxdjbh DECLARE @bh BIGINT --鎖表 --IF EXISTS(SELECT 1 FROM lshs WITH (TABLOCKX) WHERE lx=@lxAND lshdate=CONVERT(VARCHAR(10),GETDATE(),126)) -- BEGIN -- SELECT @bh = MaxLsh + 1 -- FROM dbo.Lshs -- WHERE lx = @lx -- UPDATE Lshs -- SET MaxLSH = @bh -- WHERE lx = @lx --END --ELSE --BEGIN -- UPDATE Lshs -- SET MaxLSH =1,lshdate=CONVERT(VARCHAR(10),GETDATE(),126) -- WHERE lx = @lx --end --鎖行 UPDATE Lshs SET @bh = maxlsh= CASE WHEN lshdate=CONVERT(VARCHAR(10),GETDATE(),126) THEN maxlsh+1 ELSE 1 end ,lshdate=CONVERT(VARCHAR(10),GETDATE(),126) WHERE lx = @lx --獲取編號 SET @lsh=@lx+REPLACE(CONVERT(VARCHAR(10),GETDATE(),126),'-','')+REPLICATE('0',6-LEN(@bh))+CONVERT(VARCHAR(10),@bh) IF @@error <> 0 BEGIN ROLLBACKTRAN tran_SOF_getmaxdjbh END IF @tran_point = 0 BEGIN COMMITTRAN tran_SOF_getmaxdjbh RETURN 0 END END
語句中注釋的是鎖表的方式,未注釋是用Update語句,是鎖行的操作,鎖表的操作要更占時間,當(dāng)一個表中有很多個類型時,就會排隊,等一種類型生成后,釋放表,才能繼續(xù)生成下一種類型,鎖行只鎖相同類型的,相對來說類型越多,這種優(yōu)勢越明顯。并且在短時間內(nèi)生成的單據(jù)號越多,鎖行的優(yōu)勢也越明顯。
下來,我們可以用這樣的代碼來測試一下:
classProgram { staticDictionaryyz_dic = newDictionary (); staticDictionary xs_dic = newDictionary (); staticDictionary cg_dic = newDictionary (); staticvoid GetID() { Console.WriteLine("begin"); void BuildLsh(object obj) { //定義一個時間對象 var oTime = newStopwatch(); oTime.Start(); //記錄開始時間 using (var con = newSqlConnection("DataSource=.;Initial Catalog=testlsh;Persist Security Info=True;UserID=sa;Password=******;")) { var cmd = newSqlCommand(); cmd.Connection = con; cmd.CommandText = "getlsh"; cmd.CommandType =System.Data.CommandType.StoredProcedure; var lxnum = DateTime.Now.Millisecond % 3; var lx = "YZ"; switch (lxnum) { case 0: lx = "YZ"; break; case 1: lx = "XS"; break; case 2: lx = "CG"; break; } cmd.Parameters.Add(newSqlParameter() { ParameterName ="@lx", Value = lx }); var par = newSqlParameter(); par.ParameterName = "@lsh"; par.Direction =System.Data.ParameterDirection.Output; par.SqlDbType =System.Data.SqlDbType.VarChar; par.Size = 30; cmd.Parameters.Add(par); con.Open(); cmd.ExecuteReader(); var lsh = par.Value.ToString(); switch (lxnum) { case 0: yz_dic.Add(lsh,obj.ToString()); break; case 1: xs_dic.Add(lsh,obj.ToString()); break; case 2: cg_dic.Add(lsh,obj.ToString()); break; } } oTime.Stop(); //記錄結(jié)束時間 //輸出運行時間。 Console.WriteLine($"---{obj}---程序的運行時間:{ oTime.Elapsed.TotalMilliseconds}毫秒"); } for (int i = 0; i < 2000; i++) { new System.Threading.Thread(BuildLsh).Start(i); } } publicstaticvoid Main() { GetID(); } }
可以切換存付過程中的鎖表和鎖列的兩段SQL,查看執(zhí)行的時間,有明顯的區(qū)別
鎖行結(jié)果如下(本結(jié)果只作比較,快慢與硬件有很大關(guān)系):
鎖表:
創(chuàng)新互聯(lián)www.cdcxhl.cn,專業(yè)提供香港、美國云服務(wù)器,動態(tài)BGP最優(yōu)骨干路由自動選擇,持續(xù)穩(wěn)定高效的網(wǎng)絡(luò)助力業(yè)務(wù)部署。公司持有工信部辦法的idc、isp許可證, 機房獨有T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確進(jìn)行流量調(diào)度,確保服務(wù)器高可用性。佳節(jié)活動現(xiàn)已開啟,新人活動云服務(wù)器買多久送多久。