用SQL存储过程生成唯一单据号
用SQL存储过程生成唯一单据号
在一些系统中,经理要生成单据号,为了不使多台客户端生成的单据号重复,一般要在服务端生成这种流水号,本文是在数据库中生成流水号,并且可以生成多种类型的单据号(比如销售单据号,盘点单据号,进货单据号等),利用数据库锁的原理,先看一下SQL语句:
语句中注释的是锁表的方式,未注释是用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,查看执行的时间,有明显的区别
锁行结果如下(本结果只作比较,快慢与硬件有很大关系):