c# 依照部门代号生成连续序列号且不可重复

dwtad 2017-10-06 02:13:21
c#依照部门代号生成连续序列号,举例如下:

有三个部门,部门一代号为100;部门二代号为200;部门三代号为300;

要求:
要求各个部门在建立单据时,生成一个单据编号,格式为:年份+部门代号+三位序列号,
比如部门一的第一个单据编号为:2017100001,第二个为:2017100002,第三个为:2017100003,以此类推;
比如部门二的第一个单据编号为:2017200001,第二个为:2017200002,第三个为:2017200003,以此类推;
比如部门三的第一个单据编号为:2017300001,第二个为:2017300002,第三个为:2017300003,以此类推;

注:
1.各个部门人员登录时,系统会自动识别人员所在部门,并自动抓取部门编号;
2.各个部门均会出现多人员同时操作建立单据的现象,使用max函数可能会出现重复单号问题;
3.程序允许使用数据库自动ID辅助建立序列号;

未想便捷的处理方法,所以想请有经验人士帮忙给与指点一下实现过程,非常感谢!
...全文
1130 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
ilikeff8 2017-10-09
  • 打赏
  • 举报
回复
再结合自定义的编码规则,搞个前缀后缀自增长度起始单号啥的
ilikeff8 2017-10-09
  • 打赏
  • 举报
回复
ID用GUID,单据号可以用自增 或装个sql server 2012或以上,直接用SEQUENCE http://blog.csdn.net/zeko075/article/details/47129915
dwtad 2017-10-08
  • 打赏
  • 举报
回复
引用
先插入,在取回最后的自增id!
这个跟我的使用习惯比较相像,用数据库自增ID感觉更有底;
sageing 2017-10-08
  • 打赏
  • 举报
回复
这个不错,一般是幻读的问题
xuzuning 2017-10-08
  • 打赏
  • 举报
回复
先插入,在取回最后的自增id! 如果数据库系统连自增ID 的唯一性都不能保证的话,干脆都倒闭得了
闭包客 2017-10-07
  • 打赏
  • 举报
回复
借助自增列代码量可不少,而且没有任何额外收益。其实只要在原代码加几行就可以解决的。sql 的事务机制是可以完美解决你的问题的。我迟点写示例代码。
闭包客 2017-10-07
  • 打赏
  • 举报
回复
这只是一个数据库的解决幻读的问题,你可以找找相关文档或者看看我的博客。
dwtad 2017-10-07
  • 打赏
  • 举报
回复
首先,非常感谢各位前辈的耐心指点,相信前辈们所指点之方式定是更好之处理方式,鉴于才识有限,尚未能领悟(感觉有点难); 经这两天的沉思,现已悟出一个的方法,采用传统之中规中矩sql语句并增加简易之逻辑判断,以procedure形式出现,将drpserialnum表之ID栏设为自增方式作为辅助,然后将procedure返回之结果进行相关处理并冠以部门编号,可解决当前问题; 此方法涉及之技术含量较低亦或其它问题,可能不是好的方案,其中不足之处,还望前辈们能够指出; 现在把这个procedure完整代码写于此,好让有类似需求人员有个参考: 注: 1.token组成:帐号+CpuId+diskId+macAdr+年月日时分秒毫秒+随机数 2.CpuId+broadId+macAdr:为客户端PC讯息,由客户端提供; CREATE DEFINER=`root`@`localhost` PROCEDURE `drpserialnum_procedure`(in chanel varchar(19),in shop varchar(19),in token varchar(199),in userId varchar(19)) BEGIN insert into drpserialnum(userChanel,userShop,tokens,userAcc) values (chanel,shop,token,userId); set @shopId=null; -- 1.order by ID desc limit 0,1为双重保护,谨防tokens出现重复值 select ID from drpserialnum where userChanel=chanel and userShop=shop and tokens=token and userAcc=userId order by ID desc limit 0,1 into @shopId; -- 1.简易lock查询; select count(ID) as serialNum from drpserialnum where userChanel=chanel and userShop=shop and ID<=@shopId; END 用mysql workbench简易测试如下: set @chanel="chanel_A"; set @shop="shop_A"; -- 此处token为临时测试数据,测试时,应尽量避免重复值 set @token="1234567890"; set @userId="18651500012"; call drpserialnum_procedure(@chanel,@shop,@token,@userId);
  • 打赏
  • 举报
回复
高级的分布式服务设计就不谈了,就说一般的数据库编程设计部分。 假设使用
select max(编号) from [XXX单据] where dept="1"
并且你要插入10001号记录,那么在任务彻底完毕之前,你不敢允许幻象读(其它的单据 insert 操作会让此任务产生幻象读),所以你必须使用事务保护机制来全程排斥其它单据的所有 insert 操作。这就很容易卡死了多用户系统。假设你使用
update [单据最大编号] set [编号]=@num where dept="1"
假设你要插入10001号记录,那么只是瞬间以事务方式阻塞了对这个表的脏读访问,你在向单据表插入10001号记录之前就已经将“单据最大编号”记录更新为10002号了,这就不存在需要在当前任务处理“全程”都加锁的问题了。 因此,事务中的处理不但要保证非常快(几十毫秒),而且在数据库表结构上也会避免大的查询,在处理流程上也要精细地设计异步处理能力,才能保证基本的性能。“随便查询一下数据”,那是个人使用数据库的习惯,碰到大一点的重要系统来检验时就很容易垮了。
  • 打赏
  • 举报
回复
你的这个问题,实际上从你描述来看,你是很清楚为什么要进行事务保护的,因为你清楚知道“存在重复单号”问题,这时候如果满脑子只有数据库编程的话、就只能而且必须全程仪仗事务机制。 所以,我的重点是说明,纠结于技术本身其实不是程序设计的终点,只能算是设计的起点。最差的方式是写一个统计函数而锁住一大批单据记录,好一点的方式是不锁单据记录而只是瞬间锁一下另外的“MAX编号”表,而在一个比较潮流的设计中你可能要考虑“去掉数据库思维方式”。
  • 打赏
  • 举报
回复
查询同一个部门的所有的单据记录去进行所谓的 max 计算,这就会产生幻想读错误。查询一个统一的“各部门编号表”来管理max数值,可以提高性能(根本不需要 max 统计函数),但是会产生脏读。 解决这类问题,数据库事务就是干这个事情的,是很普通的技术。除了简单地分配磁盘空间来保存数据记录和索引以外,进行数据库编程主要就是学习的原理就是事务机制、sql语言。 如果是小项目,就好像当年的12306的承包商认为国家花大价钱买贵的服务器就能解决性能问题,那么你用数据库机制来处理一般的设计问题就可以了。如果你面对的是成本压力,那么就需要更多技术,例如你可能设计一个SOA服务专门用来在内存中来统一分配流水号,这肯定就比数据库机制快1万倍速度。
雨何方 2017-10-06
  • 打赏
  • 举报
回复
SQL建立二张表: 部门表:部门ID,部门编号,部门名称。 单据表:单据ID,编号,........,部门ID 程序实现思路: 1.由用户选择部门:等选定部门后,系统记录该部门的部门ID 2.连接数据查询单据表,SELECT 编号 FROM 单据表 WHERE 部门ID=第一步记录的部门ID ORDER BY 编号 DESC 3.将此编号进行Substring,然后在序列号的部份加上1. 4.然后再格式化编号,达到你想的格式。 这样就完成了。 如果是多张表有此需求,可以写一个公用类,然后只需调用就可以了。 希望对你有所帮助。
闭包客 2017-10-06
  • 打赏
  • 举报
回复
使用串行事务,放置更新锁,锁定部门的数据后再生成新 id
  • 打赏
  • 举报
回复
数据库编程设计就是有这方面的高级课题。不要滥用数据库事务锁机制,不要随便设计什么“流水号”这类看上去很容易理解而实际上是性能杀手的机制。能用 guid 之类,要用 guid。
  • 打赏
  • 举报
回复
引用 4 楼 dwtad 的回复:
引用
你这个数字很短,我觉得都可以使用数字自增1的方式来实现,比如 insert into order (orderno) select max(orderno)+1 from order where orderno like '2017100%'
1.数字短是为了让大家更容易看清需求,实际上是不短的; 2.各个部门均会出现多人员同时操作建立单据的现象,数据量大的时候,使用max函数是否会出现重复单号问题?
使用一个专门用来记录唯一的 max 最终值的表,尚且会让所有的相关客户端卡住,那么这种把所有单据都锁死在事务中的方法、将所有单据查询语句(即使不是用来处理最大编号的)的事务都卡死的方法,更加是性能杀手。以关系数据库的方式,只有在事务中才能保证最大编号唯一,于是不得不一直死死卡住事务保护严密性,所以这样的系统适合个人玩儿,不适合大公司用。
dwtad 2017-10-06
  • 打赏
  • 举报
回复
引用
如果数字超过数学计算的长度,那在想别的方法,如果没有超过的话,就可以使用这种方法,如果你怕出现并发的问题,那么你可以使用事务执行这个语句
这种方式应该是数据提交之后生成的单据编号?后面怎样回查这个单据编号呢?要添加一个独立的签名识别列吗?因为后面还要打印这个单据中的资料;
  • 打赏
  • 举报
回复
以关系数据库操作来说,只要用一个表来记录各个部门的“最新编号”即可,根本无需用多个表。当在事务处理中,读取这个表的的记录,例如
select num from [最新编号] where dept = "1"
的时候,就会阻塞所有其它的访问 dept="1" 的数据库事务。所以数据库事务本来就是干这个事情的,这是很基本的。 不过要说说最近7、8年的事情。最近的潮流有一些变化,关系数据库的事务其实是最坑爹的,是性能的杀手。如果纠结于关系数据库事务,那么可能根本没有淘宝和天猫,所有系统都跟2011\2012年的12306一样卡死了。所以分布式大系统,根本不是关系数据库事务模式,而反而是那些依靠关系数据库排它锁模式的程序会被 ko 输。
爱在今世 2017-10-06
  • 打赏
  • 举报
回复
引用 4 楼 dwtad 的回复:
引用
你这个数字很短,我觉得都可以使用数字自增1的方式来实现,比如 insert into order (orderno) select max(orderno)+1 from order where orderno like '2017100%'
1.数字短是为了让大家更容易看清需求,实际上是不短的; 2.各个部门均会出现多人员同时操作建立单据的现象,数据量大的时候,使用max函数是否会出现重复单号问题?
如果数字超过数学计算的长度,那在想别的方法,如果没有超过的话,就可以使用这种方法,如果你怕出现并发的问题,那么你可以使用事务执行这个语句
dwtad 2017-10-06
  • 打赏
  • 举报
回复
引用
你这个数字很短,我觉得都可以使用数字自增1的方式来实现,比如 insert into order (orderno) select max(orderno)+1 from order where orderno like '2017100%'
1.数字短是为了让大家更容易看清需求,实际上是不短的; 2.各个部门均会出现多人员同时操作建立单据的现象,数据量大的时候,使用max函数是否会出现重复单号问题?
dwtad 2017-10-06
  • 打赏
  • 举报
回复
目前就是各个部门建了一张表来实现,其实部门不止3个,有点多,对应的也要建多个表,觉的有点麻烦,所以想请教是否有更聪明的方法;
加载更多回复(2)

111,082

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧