用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 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语句,是锁行的操作,锁表的操作要更占时间,当一个表中有很多个类型时,就会排队,等一种类型生成后,释放表,才能继续生成下一种类型,锁行只锁相同类型的,相对来说类型越多,这种优势越明显。并且在短时间内生成的单据号越多,锁行的优势也越明显。

下来,我们可以用这样的代码来测试一下:

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,查看执行的时间,有明显的区别

锁行结果如下(本结果只作比较,快慢与硬件有很大关系):

wKioL1kHKeyRSQ-WAAIzpbn77o0207.png-wh_50

锁表:

wKiom1kHKgKgeJg6AAI3a8Azbv4561.png-wh_50














本文转自桂素伟51CTO博客,原文链接: http://blog.51cto.com/axzxs/1920999,如需转载请自行联系原作者



相关文章
|
存储 SQL 数据库
SQL Server存储过程的优缺点
【10月更文挑战第18天】SQL Server 存储过程具有提高性能、增强安全性、代码复用和易于维护等优点。它可以减少编译时间和网络传输开销,通过权限控制和参数验证提升安全性,支持代码共享和复用,并且便于维护和版本管理。然而,存储过程也存在可移植性差、开发和调试复杂、版本管理问题、性能调优困难和依赖数据库服务器等缺点。使用时需根据具体需求权衡利弊。
522 1
|
存储 SQL 数据库
数据库sql语句-----游标和存储过程
数据库sql语句-----游标和存储过程
336 1
|
存储 SQL 数据库连接
C#程序调用Sql Server存储过程异常处理:调用存储过程后不返回、不抛异常的解决方案
本文分析了C#程序操作Sql Server数据库时偶发的不返回、不抛异常问题,并提出了解决思路。首先解析了一个执行存储过程的函数`ExecuteProcedure`,其功能是调用存储过程并返回影响行数。针对代码执行被阻塞但无异常的情况,文章总结了可能原因,如死锁、无限循环或网络问题等。随后提供了多种解决方案:1) 增加日志定位问题;2) 使用异步操作提升响应性;3) 设置超时机制避免阻塞;4) 利用线程池分离主线程;5) 通过信号量同步线程;6) 监控数据库连接状态确保可用性。这些方法可有效应对数据库操作中的潜在问题,保障程序稳定性。
1031 11
|
存储 SQL 数据库
SQL Server存储过程的优缺点
【10月更文挑战第17天】SQL Server 存储过程是预编译的 SQL 语句集,存于数据库中,可重复调用。它能提高性能、增强安全性和可维护性,但也有可移植性差、开发调试复杂及可能影响数据库性能等缺点。使用时需权衡利弊。
426 3
|
存储 SQL 缓存
SQL Server存储过程的优缺点
【10月更文挑战第22天】存储过程具有代码复用性高、性能优化、增强数据安全性、提高可维护性和减少网络流量等优点,但也存在调试困难、移植性差、增加数据库服务器负载和版本控制复杂等缺点。
802 1
|
存储 SQL 数据库
Sql Server 存储过程怎么找 存储过程内容
Sql Server 存储过程怎么找 存储过程内容
993 1
|
存储 SQL 数据库
SQL Server 临时存储过程及示例
SQL Server 临时存储过程及示例
327 3
|
存储 SQL 安全
【数据库高手的秘密武器:深度解析SQL视图与存储过程的魅力——封装复杂逻辑,实现代码高复用性的终极指南】
【8月更文挑战第31天】本文通过具体代码示例介绍 SQL 视图与存储过程的创建及应用优势。视图作为虚拟表,可简化复杂查询并提升代码可维护性;存储过程则预编译 SQL 语句,支持复杂逻辑与事务处理,增强代码复用性和安全性。通过创建视图 `high_earners` 和存储过程 `get_employee_details` 及 `update_salary` 的实例,展示了二者在实际项目中的强大功能。
360 1
|
存储 SQL 安全
|
存储 SQL 数据库
使用SQL创建视图和存储过程
使用SQL创建视图和存储过程
349 0