日期:2014-05-17  浏览次数:20437 次

生成每日唯一序号的难题
使用的数据库是sql server 2000

使用vb做了一个c/s程序,程序中有一个添加按钮,每当按这个按钮的时候,就会调用存储过程执行如下操作:(通常仅仅有操作员A使用这个添加按钮,其他人看不到这个按钮)
1 从表中挑选当日最大序号,假设最大序号是201312120010,序号永远为12位,每日从0001至9999。
2 将0010取出来转为浮点数后加1,得到11。
3 把11转换为0011后与日期拼起来,例如201312120011。
4 将201312120011插入数据库。
5 取回这个201312120011,然后显示给客户。
与此同时:
1 可能会有人在更新序号为非201312120010的序号的数据。
2 可能有人在汇总包含201312120011这个序号的表的数据。

在不知道其他客户端都在做什么的情况下:
操作员A使用添加按钮时,偶尔会发现新添加的序号还是上个序号,真是活见鬼了,这种情况是完全不能容忍的,会造成非常严重的后果。
试问高手,这种情况是如何产生的?如何解决?



------解决方案--------------------
这个序号是不是主键把,或者是没有唯一约束的把,要不给建个唯一约束,这样,如果插入的是重复值,那么就报错,至少可以保证不再插入重复值了。
------解决方案--------------------
因为就像你上面说的,从表面分析这个存储过程的流程,完全没问题,那么到底是哪个代码出了问题,最好是能掌握一定的数据,否则凭空猜测,最后也解决不了问题
------解决方案--------------------
从楼主的描述看基本没有问题,可能是写的代码质量不行.
------解决方案--------------------
个人观点:
1、你的第二步,为什么转成浮点而不是整型?没必要考虑精度问题吧?
2、有人插入,有人更新,那么隔离级别就需要考虑了。
3、你实在不能理解的话,把sql trace开启一段时间,然后累一点,周期性监控一下数据,比如10分钟一次,看看大概什么时间发生了重复,然后再从trace文件中检查那个时间段的语句。不过想一想这一步的确很累,所以只是最终做法
------解决方案--------------------
一般情况(并发性没那么大)可以:
declare @m int
select @m=isnull(right(max(dayid),4),1) from xxx where left(dayid,8)='今日如20140103'
set @m=@m+1
insert xxx (dayid,...) values (@m,...)

如果高一点的版本
使用 update ... output ... 比较保险

------解决方案--------------------
引用:
实在没招了,只能用主键设置了。

我觉得你应该在程序层面做一个错误捕捉,看看到底产生重复的时候是那个用户在那台电脑操作的,与那个用户在那台电脑生成的序号重复(这个可以做一个日志表记录每个单号是那个用户在那台电脑产生的)
这样就好跟踪原因了,我觉得你这个问题不外乎两种可能,一个是两个连接同时产生了单号(你说只有一个用户有权限,但你能否确定不会产生这个用户在不同电脑同时登陆呢)
二者就是同一个用户在同一台电脑产生了重复单号,是程序有Bug造成(很多时候往往自己认为没可能的东西都是因为程序逻辑错误造成的,这个我遇到不少,呵呵)
这类问题只可能是人为造成的,不可能是机器错误,因为电脑是不会错的,错的都是你的指令错而已