您好,登錄后才能下訂單哦!
在一些系統(tǒng)中,經(jīng)理要生成單據(jù)號,為了不使多臺客戶端生成的單據(jù)號重復(fù),一般要在服務(wù)端生成這種流水號,本文是在數(shù)據(jù)庫中生成流水號,并且可以生成多種類型的單據(jù)號(比如銷售單據(jù)號,盤點(diǎn)單據(jù)號,進(jìn)貨單據(jù)號等),利用數(shù)據(jù)庫鎖的原理,先看一下SQL語句:
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ù)點(diǎn) 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)一個表中有很多個類型時,就會排隊(duì),等一種類型生成后,釋放表,才能繼續(xù)生成下一種類型,鎖行只鎖相同類型的,相對來說類型越多,這種優(yōu)勢越明顯。并且在短時間內(nèi)生成的單據(jù)號越多,鎖行的優(yōu)勢也越明顯。
下來,我們可以用這樣的代碼來測試一下:
classProgram { staticDictionary<string, string> yz_dic = newDictionary<string, string>(); staticDictionary<string, string> xs_dic = newDictionary<string, string>(); staticDictionary<string, string> cg_dic = newDictionary<string, string>(); 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é)束時間 //輸出運(yùn)行時間。 Console.WriteLine($"---{obj}---程序的運(yùn)行時間:{ 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)系):
鎖表:
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。