用SQL存储过程生成唯一单据号

 
 

在一些系统中,经理要生成单据号,为了不使多台客户端生成的单据号重复,一般要在服务端生成这种流水号,本文是在数据库中生成流水号,并且可以生成多种类型的单据号(比如销售单据号,盘点单据号,进货单据号等),利用数据库锁的原理,先看一下SQL语句:

  1.  
    CREATE TABLE [dbo].[Lshs](
  2.  
    [MAXLSH] [BIGINT] NULL,
  3.  
    [LSHDate] [DATETIME] NULL,
  4.  
    [LX] [NVARCHAR](6) NULL
  5.  
    ) ON [PRIMARY]
  1.  
    CREATE PROC [dbo].[getlsh]
  2.  
        @lx VARCHAR(6) ,
  3.  
        @lsh VARCHAR(30) OUTPUT
  4.  
    AS
  5.  
        BEGIN
  6.  
     --启动事务处理
  7.  
            DECLARE@tran_point INT         --控制事务嵌套
  8.  
            SET @tran_point = @@trancount   --保存事务点
  9.  
            IF @tran_point = 0
  10.  
                BEGINTRAN tran_SOF_getmaxdjbh
  11.  
            ELSE
  12.  
                SAVETRAN tran_SOF_getmaxdjbh
  13.  
     
  14.  
            DECLARE @bh BIGINT
  15.  
            --锁表
  16.  
            --IF EXISTS(SELECT 1 FROM lshs WITH (TABLOCKX) WHERE lx=@lxAND lshdate=CONVERT(VARCHAR(10),GETDATE(),126))
  17.  
         --   BEGIN
  18.  
     --     SELECT  @bh = MaxLsh  + 1 
  19.  
     --     FROM    dbo.Lshs 
  20.  
     --     WHERE   lx = @lx  
  21.  
     --     UPDATE  Lshs
  22.  
     --     SET     MaxLSH = @bh  
  23.  
     --     WHERE   lx = @lx 
  24.  
            --END
  25.  
            --ELSE
  26.  
            --BEGIN
  27.  
     --     UPDATE  Lshs
  28.  
     --     SET     MaxLSH =1,lshdate=CONVERT(VARCHAR(10),GETDATE(),126)
  29.  
     --     WHERE   lx = @lx 
  30.  
            --end
  31.  
     
  32.  
     
  33.  
            --锁行
  34.  
            UPDATE  Lshs
  35.  
            SET    @bh = maxlsh= CASE WHEN lshdate=CONVERT(VARCHAR(10),GETDATE(),126) THEN maxlsh+1 ELSE 1 end ,lshdate=CONVERT(VARCHAR(10),GETDATE(),126)
  36.  
            WHERE   lx = @lx 
  37.  
            --获取编号
  38.  
            SET @lsh=@lx+REPLACE(CONVERT(VARCHAR(10),GETDATE(),126),'-','')+REPLICATE('0',6-LEN(@bh))+CONVERT(VARCHAR(10),@bh)
  39.  
     
  40.  
            IF @@error <> 0
  41.  
                BEGIN
  42.  
                    ROLLBACKTRAN tran_SOF_getmaxdjbh
  43.  
                END
  44.  
     
  45.  
            IF @tran_point = 0
  46.  
                BEGIN
  47.  
                    COMMITTRAN tran_SOF_getmaxdjbh
  48.  
                    RETURN 0
  49.  
                END
  50.  
        END

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

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

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

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

用SQL存储过程生成唯一单据号的更多相关文章

  1. .NET 6 在小并发下如何生成唯一单据号

    一.场景介绍 小并发下要解决生成单据号的问题,会碰到哪些问题呢?,接下来让我们一探究竟[这是小并发的解决方案,大家有更好的做好可以一起讨论分享]. 之所以叫小并发:是因为确实是小并发场景的应用模式,一 ...

  2. php生成唯一订单号

    支持更改长度/** * 生成唯一订单号 * */ function build_order_no(){ return date('Ymd').substr(implode(NULL, array_ma ...

  3. PHP生成唯一会员卡号

    我们将0-Z(0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ)分别代表数值0-35,如字母Z代表35.这样的话我要得到一个5位的编号,最大信息量就是36的5次方了,36^5 ...

  4. SQL存储过程生成顺序编码

    一.第一种方式 USE [WJKC]GO/****** Object:  StoredProcedure [dbo].[Address_GetCode1]    Script Date: 2016/3 ...

  5. C#生成唯一订单号

    今天系统出了一个问题,发现生成的订单号存在重复的情况了,这是要命的bug,不马上解决,就会有投诉了 经过改进后的代码我先简单的放一下,后面在慢慢的写清楚整个流程 string key = " ...

  6. mysql使用触发器生成唯一订单号,

    需求:订单号唯一,并且期望是时间格式加其他字符串, 实现:采用触发机制,在新增时根据新增id值加1作为订单生成的随机且确定唯一的数,因为id唯一: 遇到问题:新增时不能提前知道id值, 解决:取到当前 ...

  7. SQL 存储过程生成

    use workflow; GO /****** 对象: StoredProcedure [dbo].[pro_GenerateProGet] 脚本日期: 08/03/2012 11:26:43 ** ...

  8. 用SQL语句生成唯一标识

    以前都是在代码中生成GUID值,然后保存到数据库中去,今天发现用sql也能生成GUID值,觉得很新奇,所以记下来. sellect newid();  //得到的即为GUID值 此sql内置函数返回的 ...

  9. php生成唯一订单号的方法

    第一种 $danhao = date('Ymd') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT); 第二种 $danhao = date('Ym ...

随机推荐

  1. AcWing 107. 超快速排序(归并排序 + 逆序对 or 树状数组)

    在这个问题中,您必须分析特定的排序算法----超快速排序. 该算法通过交换两个相邻的序列元素来处理n个不同整数的序列,直到序列按升序排序. 对于输入序列9 1 0 5 4,超快速排序生成输出0 1 4 ...

  2. hibernate一对多关联映射

    一对多关联映射 映射原理 一对多关联映射和多对一关联映射的映射原理是一致的,都是在多的一端加入一个外键,指向一的一端.关联关系都是由多端维护,只是在写映射时发生了变化. 多对一和一对多的区别 多对一和 ...

  3. gromacs2018使用踩坑记--insert-molecules

    1] gmx插入分子[ -f [<.gro / .g96 / ...>] ] [ -ci [<.gro / .g96 / ...>] ] [ -ip [<.dat> ...

  4. hdu5747 Aaronson 贪心

    Aaronson Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total ...

  5. 学习笔记 - Git

    学习参考网址:https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000 Git是目前世界上 ...

  6. 如何保存 Activity 的状态?

    Activity 的状态通常情况下系统会自动保存的,只有当我们需要保存额外的数据时才需要使用到这样的功能.一般来说, 调用 onPause()和 onStop()方法后的 activity 实例仍然存 ...

  7. 保存json数据到本地和读取本地json数据

    private void saveJson(JsonBean bean) { File file = new File(getFilesDir(), "json.txt"); Bu ...

  8. 配置XFCE4的时钟显示格式

    配置XFCE4的时钟显示格式,如下1: %b%d %A, %R:%S 显示结果: 10月09日 星期三,09:50:45 如下2: [%Y年%b %d日] [%A],第%V周,第%j天 显示结果: 2 ...

  9. python--006

    一.函数的作用域 1.作用域在定义函数时就已经固定住了,不会随着调用位置的改变而改变 例一: name='alex' def foo(): name='lhf' def bar(): print(na ...

  10. Unity中的动画系统和Timeline(4) AvatarMask和IK动画

    AvatarMask(骨骼遮罩) 在前面角色动画的基础上,角色在奔跑过程中捡起一块木头,双手要抱着这块木头.如果使用前面的方法,直接切换动画,那么就只剩下抱木头的动画,其它动画就没了.这时我们要使用下 ...