用SQL存储过程生成唯一单据号
用SQL存储过程生成唯一单据号
在一些系统中,经理要生成单据号,为了不使多台客户端生成的单据号重复,一般要在服务端生成这种流水号,本文是在数据库中生成流水号,并且可以生成多种类型的单据号(比如销售单据号,盘点单据号,进货单据号等),利用数据库锁的原理,先看一下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
- --启动事务处理
- 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语句,是锁行的操作,锁表的操作要更占时间,当一个表中有很多个类型时,就会排队,等一种类型生成后,释放表,才能继续生成下一种类型,锁行只锁相同类型的,相对来说类型越多,这种优势越明显。并且在短时间内生成的单据号越多,锁行的优势也越明显。
下来,我们可以用这样的代码来测试一下:
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存储过程生成唯一单据号的更多相关文章
- .NET 6 在小并发下如何生成唯一单据号
一.场景介绍 小并发下要解决生成单据号的问题,会碰到哪些问题呢?,接下来让我们一探究竟[这是小并发的解决方案,大家有更好的做好可以一起讨论分享]. 之所以叫小并发:是因为确实是小并发场景的应用模式,一 ...
- php生成唯一订单号
支持更改长度/** * 生成唯一订单号 * */ function build_order_no(){ return date('Ymd').substr(implode(NULL, array_ma ...
- PHP生成唯一会员卡号
我们将0-Z(0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ)分别代表数值0-35,如字母Z代表35.这样的话我要得到一个5位的编号,最大信息量就是36的5次方了,36^5 ...
- SQL存储过程生成顺序编码
一.第一种方式 USE [WJKC]GO/****** Object: StoredProcedure [dbo].[Address_GetCode1] Script Date: 2016/3 ...
- C#生成唯一订单号
今天系统出了一个问题,发现生成的订单号存在重复的情况了,这是要命的bug,不马上解决,就会有投诉了 经过改进后的代码我先简单的放一下,后面在慢慢的写清楚整个流程 string key = " ...
- mysql使用触发器生成唯一订单号,
需求:订单号唯一,并且期望是时间格式加其他字符串, 实现:采用触发机制,在新增时根据新增id值加1作为订单生成的随机且确定唯一的数,因为id唯一: 遇到问题:新增时不能提前知道id值, 解决:取到当前 ...
- SQL 存储过程生成
use workflow; GO /****** 对象: StoredProcedure [dbo].[pro_GenerateProGet] 脚本日期: 08/03/2012 11:26:43 ** ...
- 用SQL语句生成唯一标识
以前都是在代码中生成GUID值,然后保存到数据库中去,今天发现用sql也能生成GUID值,觉得很新奇,所以记下来. sellect newid(); //得到的即为GUID值 此sql内置函数返回的 ...
- php生成唯一订单号的方法
第一种 $danhao = date('Ymd') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT); 第二种 $danhao = date('Ym ...
随机推荐
- oracle 获取时间
1.获取当前时间的前24小时的各小时时间段 select to_char(to_date(to_char(sysdate ) ,'yyyy-mm-dd hh24') || ':00:00','yyyy ...
- 第八周课程总结 & 实验报告(六)
第八周课程总结 一.包装类 介绍 装箱与拆箱 应用 二.异常 基本概念 基本格式 异常类的继承结构 throws关键字 throw关键字 Exception类和RuntimeException类 自定 ...
- Mysql 实用语句记录
都是工作中遇到的需求,但不是常用sql,特此记录,方便以后使用: 1.将指定列的数据拼起来存到某一列 UPDATE table_name SET b_col_name=CONCAT(b_col_nam ...
- Java反序列化漏洞从入门到深入(转载)
前言 学习本系列文章需要的Java基础: 了解Java基础语法及结构(菜鸟教程) 了解Java面向对象编程思想(快速理解请上知乎读故事,深入钻研建议买本<疯狂Java讲义>另外有一个刘意老 ...
- KahnProcessNetwork的Python实现
用Pytho实现了一个Kahn Process Network: 思路: 用Python的list模拟queue. 每个channel一个queue 用一个list (fgLog)来记录所有push到 ...
- python + 爬虫 + fiddler + 夜神模拟器 爬取app(1)
抓包 抓包是爬虫里面经常用到的一个词,完整的应该叫做抓取数据请求响应包 ,而Fiddler这款工具就是干这个的 普通https抓包设置 打开Fiddler ------> Options .然后 ...
- 113路径总和II
题目: 给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径. 来源: https://leetcode-cn.com/problems/path-sum-ii/ 法一: ...
- python学习笔记:(十五)迭代器和生成器
一.迭代器: 1.迭代器是python最强大的功能之一,是访问集合元素的一种方式. 2.迭代器是一个可以记住遍历的位置的对象. 3.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问结束.迭代 ...
- 简单的servlet下载
<servlet> <servlet-name>servletTest</servlet-name> <servlet-class>com.shangs ...
- java:JavaScript2:(setTimeout定时器,history.go()前进/后退,navigator.userAgent判断浏览器,location.href,五种方法获取标签属性,setAttribute,innerHTML,三种方法获取form表单信息,JS表单验证,DOM对象,form表单操作)
1.open,setTimeout,setInterval,clearInterval,clearTimeout <!DOCTYPE> <html> <head> ...