用SQL存储过程生成唯一单据号
在一些系统中,经理要生成单据号,为了不使多台客户端生成的单据号重复,一般要在服务端生成这种流水号,本文是在数据库中生成流水号,并且可以生成多种类型的单据号(比如销售单据号,盘点单据号,进货单据号等),利用数据库锁的原理,先看一下SQL语句:
1
2
3
4
5
|
CREATE TABLE [dbo].[Lshs](
[MAXLSH] [ BIGINT ] NULL ,
[LSHDate] [DATETIME] NULL ,
[LX] [NVARCHAR](6) NULL
) ON [ PRIMARY ]
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
CREATE PROC [dbo].[getlsh]
@lx VARCHAR (6) ,
@lsh VARCHAR (30) OUTPUT
AS BEGIN
--启动事务处理
DECLARE @tran_point INT --控制事务嵌套
SET @tran_point = @@trancount --保存事务点
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 [email protected] 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 @[email protected]+ 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语句,是锁行的操作,锁表的操作要更占时间,当一个表中有很多个类型时,就会排队,等一种类型生成后,释放表,才能继续生成下一种类型,锁行只锁相同类型的,相对来说类型越多,这种优势越明显。并且在短时间内生成的单据号越多,锁行的优势也越明显。
下来,我们可以用这样的代码来测试一下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
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(); //记录结束时间
//输出运行时间。
Console.WriteLine($ "---{obj}---程序的运行时间:{ oTime.Elapsed.TotalMilliseconds}毫秒" );
}
for ( int i = 0; i < 2000; i++)
{
new System.Threading.Thread(BuildLsh).Start(i);
}
}
publicstaticvoid Main()
{
GetID();
}
} |
可以切换存付过程中的锁表和锁列的两段SQL,查看执行的时间,有明显的区别
锁行结果如下(本结果只作比较,快慢与硬件有很大关系):
锁表:
本文转自桂素伟51CTO博客,原文链接: http://blog.51cto.com/axzxs/1920999,如需转载请自行联系原作者