SQLSERVER之高灵活的业务单据流水号生成

最近的工作中要用到流水号,而且业务单据流水号生成的规则分好几种,并非以前那种千篇一律的前缀+日期+流水号的简单形式,经过对业务的分析,以及参考网上程序员的N种方法,整理出了一个表结构和存储过程

思路分析:

1.大体上,流水号都遵循近似这样的一般规则:流水号 = 前缀+动态内容+日期+中缀+流水号+后缀

这里的动态内容是通过参数传入流水号生成存储过程的,比如动态内容为科室+组别,这个科室和组别是动态的,每一张单可能都不同,是根据登录人组织信息得到的

2.流水号生成要控制并发

并发的话,网上资料大多都是加锁提示,比如holdlock,xlock,rowlock等等,但其它人又说最好不要加提示,锁提示,索引提示能不加就不加,因为这个数据库可以自动判断,比如是锁定整张表,还是锁定某几行等等,所以我直接设定了事务级别,我还是没怎么搞清楚到底设置为repeatable read 还是 serializable,经过分析,个人认为还是设定为serializable,即串行化比较保险,相当于所有事务都按队列进行,总是有排序的,但缺点是性能很差,当然也要看情况,一天几张单,几十张单,几百张单就根本不用考虑性能问题了.如果是大型系统,估计也不是这样搞法,至于大型系统是如何搞的,我真不知道(当然很想知道,比如淘宝,当当的订单号是如何生成的???)

其它的还暂未想到,到时候碰到再更改,请各位同行们指点,以求改进

脚本代码如下:

  1  --流水号表
2 --流水号一般规则:流水号 = 前缀+动态内容+日期+中缀+流水号+后缀。
3 --动态内容一般是执行存储过程取流水号的时候动态传入的
4 if object_id('t_sequence_number') is not null
5 drop table t_sequence_number
6 go
7
8 create table t_sequence_number(
9 id int identity
10 ,sequence_type varchar(50) not null --哪种类型的流水号,为求方便,默认是表名
11 ,sequencenumber_len int not null --流水号长度 如长度为4,表示'0000',长度为7,表示'0000000'等等
12 ,reset_type varchar(50) not null --归一类型,'year'表示按年,'month'表示按月,'day'表示按日,归一类型与日期模板三个字段是有约束的,
如果是day,则年,月,日都不能为空,如果为month,则年月不能为空,如果为'',表示不要日期
13 ,separator varchar(50) not null --流水号各部分分隔符
14 ,prefix varchar(50) not null --前缀
15 ,part_year_fmt varchar(50) not null --日期模板年份 可以是:yyyy,yy,
16 ,part_month_fmt varchar(50) not null --日期模板月份 可以是:mm,m等等
17 ,part_day_fmt varchar(50) not null --日期模板日期 可以是:dd,d等等
18 ,midfix varchar(50) not null --中缀
19 ,cur_max_sequence_number int not null --当前最大流水号值
20 ,cur_max_date datetime null --当前最大日期
21 ,suffix varchar(50) not null --后缀
22
23 ,constraint uq_t_sequence_number_sequence_type unique (sequence_type)
24 ,constraint pk_t_sequence_number_id primary key (id)
25 ,constraint chk_t_sequence_number_reset_type check (reset_type in ('year','month','day',''))
26 ,constraint chk_t_sequence_number_part_year_fmt check (part_year_fmt in ('yyyy','yy',''))
27 ,constraint chk_t_sequence_number_part_month_fmt check (part_month_fmt in ('mm','m',''))
28 ,constraint chk_t_sequence_number_part_day_fmt check (part_day_fmt in ('dd','d',''))
29 ,constraint chk_t_sequence_number_reset_type_map_fmt
check ( reset_type = ''
or charindex(left(reset_type,1),isnull(part_year_fmt,'')+isnull(part_month_fmt,'')+isnull(part_day_fmt,''))>0)
30 ,constraint chk_t_sequence_number_cur_max_date check ( reset_type = ''
or (reset_type<>'' and cur_max_date is not null))
32 )
33 alter table t_sequence_number
34 add constraint def_t_sequence_number_sequencenumber_len default 4 for sequencenumber_len
35
36 alter table t_sequence_number
37 add constraint def_t_sequence_number_reset_type default ('day') for reset_type
38
39 alter table t_sequence_number
40 add constraint def_t_sequence_number_separator default ('') for separator
41
42 alter table t_sequence_number
43 add constraint def_t_sequence_number_prefix default ('') for prefix
44
45 alter table t_sequence_number
46 add constraint def_t_sequence_number_part_year_fmt default ('yyyy') for part_year_fmt
47
48 alter table t_sequence_number
49 add constraint def_t_sequence_number_part_month_fmt default ('mm') for part_month_fmt
50
51 alter table t_sequence_number
52 add constraint def_t_sequence_number_part_day_fmt default ('dd') for part_day_fmt
53
54 alter table t_sequence_number
55 add constraint def_t_sequence_number_midfix default ('') for midfix
56
57 alter table t_sequence_number
58 add constraint def_t_sequence_number_cur_max_sequence_number default (0) for cur_max_sequence_number
59
60 alter table t_sequence_number
61 add constraint def_t_sequence_number_cur_max_date default (getdate()) for cur_max_date
62
63 alter table t_sequence_number
64 add constraint def_t_sequence_number_suffix default ('') for suffix
65
66 go
67
68 if object_id('sp_Get_Sequence_Number') is not null
69 drop proc sp_Get_Sequence_Number
70 go
71
72 create procedure sp_Get_Sequence_Number
73 @sequence_type varchar(50) --流水号类别
74 ,@count int = 1 --获取几个序列号
75 ,@dynamic_content varchar(50) = '' --动态内容
76 as
77 begin
78 /*
79 --流水号一般规则:流水号 = 前缀+动态内容+日期+中缀+流水号+后缀。
80 --动态内容一般是执行存储过程取流水号的时候动态传入的
81 插入内容示例:
82 insert into t_sequence_number(sequence_type,sequencenumber_len,reset_type,separator,prefix,part_year_fmt,
part_month_fmt,part_day_fmt,midfix,cur_max_sequence_number,cur_max_date,suffix)
83 values('CarApply',4,'day','','LA','yy','mm','dd','',0,getdate(),'')
84
85 执行示例:exec sp_Get_Sequence_Number 'CarApply'
86
87 */
88 set nocount on;
89 set transaction isolation level serializable;
90
91 declare @currentdate datetime
92 ,@sequencenumber_len int
93 ,@reset_type varchar(50)
94 ,@separator varchar(50)
95 ,@prefix varchar(50)
96 ,@part_year_fmt varchar(50)
97 ,@part_month_fmt varchar(50)
98 ,@part_day_fmt varchar(50)
99 ,@midfix varchar(50)
100 ,@cur_max_sequence_number int
101 ,@cur_max_sequence_number_firt_bak int
102 ,@cur_max_date datetime
103 ,@suffix varchar(50)
104 ,@datestr varchar(50);
105
106 declare @seqtable table(seqnum varchar(50),orderno int);
107
108 begin tran
109
110 --读取配置信息
111 select @currentdate = getdate()
112 ,@sequencenumber_len = sequencenumber_len
113 ,@reset_type = reset_type
114 ,@separator = separator
115 ,@prefix = prefix
116 ,@part_year_fmt = isnull(part_year_fmt,0)
117 ,@part_month_fmt = part_month_fmt
118 ,@part_day_fmt = part_day_fmt
119 ,@midfix = midfix
120 ,@cur_max_sequence_number = cur_max_sequence_number
121 ,@cur_max_sequence_number_firt_bak = cur_max_sequence_number
122 ,@cur_max_date=cur_max_date
123 ,@suffix = suffix
124 ,@datestr = ''
125 from t_sequence_number where sequence_type=@sequence_type;
126
127 if @@rowcount = 0
128 begin
129 raiserror('无相应的流水号类别,请确认@sequence_type参数值是否正确!',16,1);
130 end
131
132 if @reset_type<>''
133 begin
134 set @datestr = case @part_year_fmt
when 'yyyy' then cast(year(getdate()) as varchar(50)) else right(cast(year(getdate()) as varchar(50)),2) end
135 + case @part_month_fmt
when 'mm' then right('0'+ cast(month(getdate()) as varchar(50)),2) else cast(month(getdate()) as varchar(50)) end
136 + case @part_day_fmt
when 'dd' then right('0'+ cast(day(getdate()) as varchar(50)),2) else cast(day(getdate()) as varchar(50)) end
137
138 end
139
140 if convert(varchar(8), @currentdate, 112) = convert(varchar(8), @cur_max_date, 112)
141 set @cur_max_sequence_number = @cur_max_sequence_number + @count; --累加
142 else
143 begin
144 set @cur_max_sequence_number = 1; --归1
145 set @cur_max_sequence_number_firt_bak = 0;
146 end
147
148 while @count >=1
149 begin
150 insert into @seqtable values(
151 @prefix
152 + @separator
153 + @dynamic_content
154 + case @dynamic_content when '' then '' else @separator end
155 + @datestr
156 + case @datestr when '' then '' else @separator end
157 + @midfix
158 + case @midfix when '' then '' else @separator end
159 + right( replicate('0',@sequencenumber_len)
+cast(@cur_max_sequence_number_firt_bak+@count as varchar(50)),@sequencenumber_len)
160 + case @suffix when '' then '' else @separator end
161 + @suffix
162 ,@count
163 )
164
165 set @count = @count - 1;
166
167 end
168
169 update t_sequence_number
170 set cur_max_date = @currentdate
171 ,cur_max_sequence_number=@cur_max_sequence_number
172 where sequence_type=@sequence_type;
173
174 commit tran
175
176 --获取流水号
177 select seqnum from @seqtable order by orderno asc
178 end

SQLSERVER之高灵活的业务单据流水号生成的更多相关文章

  1. SSM框架学习之高并发秒杀业务--笔记5-- 并发优化

    前几节终于实现了这个高并发秒杀业务,现在问题是如何优化这个业务使其能扛住一定程度的并发量. 一. 优化分析 对于整个业务来说,首先是分析哪些地方会出现高并发,以及哪些地方会影响到了业务的性能.可能会出 ...

  2. 仿QQ空间和微信朋友圈,高解耦高复用高灵活

    先看看效果: 用极少的代码实现了 动态详情 及 二级评论 的 数据获取与处理 和 UI显示与交互,并且高解耦.高复用.高灵活. 动态列表界面MomentListFragment支持 下拉刷新与上拉加载 ...

  3. 金蝶K/3 跟踪语句_业务单据

    跟踪语句_业务单据_BOM select * from t_TableDescription where Ftablename like '%ICBOM%' order by FFieldName o ...

  4. [K/3Cloud] 创建一个业务单据表单插件

    概念 创建一个业务单据插件,处理单据的相关控制逻辑. 示例 新建一个类,继承自单据插件基类Kingdee.BOS.Core.Bill.PlugIn.AbstractBillPlugIn. using ...

  5. Winform通用模块之流水号生成

    打算接下来的时间里把自己觉得用起来还比较好用的通用模块,在这里向大家介绍一下,如果你有更好的想法时,也希望你不吝指点. 1.数据库表及存储过程 在介绍这个通用流水号生成的模块前,我们先来看一下其相关的 ...

  6. 基于mysql的单据号生成(前缀+日期+自增id+后缀)

    介绍 本次采用mysql处理,性能不是很好,对于高并发有要求的建议不要采用公司一个小项目,需要生成一个单据号,格式为: 日期 + 每日重新自增号,自己考虑了一下每日自增需要考虑并发和持久问题,两种数据 ...

  7. Winform开发框架之单据窗体生成(主从表,流水单号)

    源码地址:https://github.com/GarsonZhang/GZFramework.ShareDemo 前言 1.在开始本节前请先重置代码为 chapter-03-start 懒人地址:h ...

  8. 基于Oracle Sequence的流水号生成规则

    流水号在各种系统中随处可见,一般都是使用自增.年月日时分秒+自增.UUID等,要么纯数字,要么纯字母,这种流水号缺乏一定的辨识度. 下面为大家介绍一种具有辨识度的流水号的生成方式:领域或者应用的标识 ...

  9. 高并发 php uniqid 用md5生成不重复唯一标识符方案

    高并发 php uniqid 用md5生成不重复唯一标识符方案uniqid() 函数基于以微秒计的当前时间,生成一个唯一的 ID.uniqid(prefix,more_entropy)prefix 可 ...

随机推荐

  1. LSM树存储模型

    ----<大规模分布式存储系统:原理解析与架构实战>读书笔记 之前研究了Bitcask存储模型,今天来看看LSM存储模型,两者尽管同属于基于键值的日志型存储模型.可是Bitcask使用哈希 ...

  2. SEO 优化,网站推广优化教程100条(SEO,网站关键字优化,怎么优化网站,如何优化网站关键字)

    这篇文章不错.  http://www.cnblogs.com/zangdalei/archive/2010/08/31/1814047.html 看了一半之后的,觉得不太靠谱,很多都不懂. 于是 找 ...

  3. Android 记录的(MediaRecorder)而播放(MediaPlayer)

    经MediaRecorder和MediaPlayer实现声音记录和回放,代码比较简单,直接附着到代码. xml文档面对只有四个button不贴. UI watermark/2/text/aHR0cDo ...

  4. 一些常用的jquery数字正则表达式

    使用 <script type="text/javascript"> function validate(){ var reg = new RegExp("^ ...

  5. iOS_23_undress Girl

    最后效果图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcHJlX2VtaW5lbnQ=/font/5a6L5L2T/fontsize/400/fill ...

  6. sql点滴41—MyISAM 和 InnoDB 讲解

    原文:sql点滴41-MyISAM 和 InnoDB 讲解 InnoDB和MyISAM是许多人在使用MySQL时最常用的两个表类型,这两个表类型各有优劣,视具体应用而定.基本的差别为:MyISAM类型 ...

  7. 快速构建Windows 8风格应用29-捕获图片与视频

    原文:快速构建Windows 8风格应用29-捕获图片与视频 引言 本篇博文主要介绍Windows 8中相机的概念.捕获图片与视频的基本原理.如何实现捕获图片与视频.相机最佳实践. 一.相机 关于相机 ...

  8. Fedora 20 Gnome安装及配置记录

    下载了F20的Gnome版,原先安装的是19KDE的,原因是昨晚看书,觉得电脑开着也没什么事情,倒不如看看能不能升级或下载点东西 原先是KDE的界面,所以打算换换风格,使用下Gnome,不过更换过程总 ...

  9. waitFor和waitForAny的实现

    waitFor和waitForAny的实现 在实现waitFor方法之前,我们先要搞明白下面这些问题: 1. waitFor方法的形参有限制吗? 没有!如果形参是Task类型,不应该启动Task,如果 ...

  10. In C# 代码实现

    SOLID 设计原则 In C# 代码实现   [S] Single Responsibility Principle (单一职责原则) 认为一个对象应该仅只有一个单一的职责 namespace Si ...