如何生成连续不重复的序列号
B/S模式下,多客户端访问,生成连续不重复的序列号。请高手指点如何实现。
我想在客户生成一串由数字组成的字符串放到数据库中一列当做单据的序列号,每次生成的序列号存到数据库后都是连续不重复的。当然保存到数据库后删除数据造成的号码断号不用考虑。
请教大侠们是如何实现的?
[解决办法]
考虑以时间,时分秒来区分,不过也会出现同秒的重复,还可以使用GUID
[解决办法]
年月日时分秒+10位随机数,再进行MD5加密
[解决办法]
建一个表,用一个字段储存最后一次生成的序号,如果需要按日期重新开始,那就再存个日期
每次获取新序列号时开始一个新事务,更新序列号+1,然后select出来作为新序号用。
因为每次都有事务,并且是先更新再查询,可以保证不会有重复数字生成。
代码就不贴了,也就几行而已。
[解决办法]
如果同一时间的话,请等待,等待一个生成后在去生成另一个啊
[解决办法]
很多种方法。
假设你就是使用SQL Server,以它的默认事务控制级别,可以确保不会进行脏读。那么你可以为每一个业务表单独设计一个“流水号”表,这个表只有一列字段,而且只有一行,保存了最大流水号。当你写一个业务记录时,在同一个事务中,为流水号+1,并将新的流水号写入业务数据记录,然后事务才结束。在事务结束之前,读取同一个流水号表最大流水号的其它事务会等待。
许多其它的数据库(比如Oracle)默认都不是这么严格的级别。所以这个方法并不能用在Oracle、Mysql等上面。当然NoSQL更不能。
实际上流水号并不是必须在保存业务数据时必须立刻赋值的系统编号(就像上面说的GUID编号可以作为与业务无关的系统编号)。你把一个业务数据保存了,及时没有流水号,那么也可以通过真正的记录唯一号来存取记录。许多业务实际上甚至会事后还修改流水号。再比如,有人想当然地把发票号当作数据库记录的唯一编号。他没有想到用户可能会发现录入错了发票号,而需要修改。所以把业务意义上的编号当作与业务无关的记录编号是错误的。
了解这个道理,那么其实有很多其它的解决办法就非常顺理成章了。比如你可以让一个程序去自动搜索还没有编流水号的记录,然后给记录编写流水号。整个系统中只要保证只有一个程序去编流水号,而不是并发的,就没有问题。而你保存业务记录时,并不需要立刻返回带有流水号的记录。当你去查询、刷新业务记录时,可能后台的那个程序刚好编完了这个流水号,于是就显示出来了。就算它运行很慢,你在查询页面上也可以刷新一下,直到看到编写好的流水号。
[解决办法]
我建议楼主用年月日时分秒+5位随机数去生成
同时在数据库检测一下
如果存在,则+1,不存在则加入
不会有问题!
[解决办法]
用户ID + 客户端IP + 年月日时分秒 + 检测
[解决办法]
两种方法:
1.建一个序号字段,每次读取时+1再放回去,当然要用事务处理的。测试过没问题。生成的号码可读性强。
2.web的可以用SESSIONSID+年月日时分秒和毫秒。这样直接可以用,但是得到的号码太长了。
[解决办法]
不能加随机数,否则无法连续。
这其实最好实现了,因为数据库自己有同步锁,防止多人操作修改同一个数据,那么只要将连续序号记录在数据库中即可,每次使用序号+1,一条UPDATE语句即可实现:
UPDATE TABLE1 SET @SNO = SNO = SNO+1 WHERE CODE = '序号'
[解决办法]
package com.rockwell.askperformance;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;public class IdSequence { static final String path="C:\\IdSequence.ser"; public static long getId(){ ObjectInputStream in=null; Long lg=3l; try { in = new ObjectInputStream(new FileInputStream(path)); lg=(Long)in.readObject(); in.close(); } catch (FileNotFoundException e) { e.printStackTrace(); ObjectOutputStream out = null; try { out = new ObjectOutputStream(new FileOutputStream(path)); out.writeObject(1l); out.close(); lg=1l; } catch (IOException e1) { e1.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return lg; } public static synchronized void setId(){ Long lg=getId()+1; ObjectOutputStream out = null; try { out = new ObjectOutputStream(new FileOutputStream(path)); out.writeObject(lg); out.close(); } catch (IOException e) { e.printStackTrace(); } } public static void main(String [] args){// IdSequence.setId(); System.out.println(IdSequence.getId()); }}
[解决办法]
string flcrdhString = ""; string datstr = DateTime.Now.ToString("yyyy/MM/dd").Replace("-", ""); DataTable dt_maxdl = AppCodeDataBase.dataTable("select isnull(replace(right(str(convert(int,max(substring(flcrdh,10,3)))+1),3),' ','0'),'0001') as lsh from raybendbase..ck_flcrmx where flcrdh like 'F" + datstr.ToString().Trim() + "'", StockDS); if (dt_maxdl.Rows.Count == 0) { flcrdhString = "F" + datstr.ToString().Trim() + "001"; } else { flcrdhString = "F" + datstr.ToString().Trim() + dt_maxdl.Rows[0]["lsh"].ToString().Trim(); } Response.Write(flcrdhString.ToString());
[解决办法]
最近正好在做这个功能给北京联通。
SE的设计思路是创建一个线程,使用生产者与消费者模式去读取生成的每一个自增长的账号。池中在系统启动的时候加载1000个自增长账号(池长度可配置),使用量达到80%启动生产者进行生产账号。
这块功能已经完成已经在北京试用 具体实现不明说了。大概意思已经描述了。
至于上面说的时间戳,仅仅是可以考虑,但是并发量很大的时候势必要添加检查数据库校验。
[解决办法]
SQL codeSelect replace(CONVERT(varchar(100), GETDATE(), 112)+ CONVERT(varchar(100), GETDATE(), 114),':','')+ right('00'+rtrim(abs(CHECKSUM(NEWID())%100+1)),2)
[解决办法]
自己做序列,建个单号表, 每次生成表从这里面拿一个
切不可从数据库里取最大值,你会崩溃的
[解决办法]
我以前做过个Sequence的类,主要思想如下:
1)在数据库有一个表,存放最后一次的Sequence的值,初始值为0,这个表有个字段是timestamp类型的。
2)每次更新的时候先读取这条记录,更新的时候加个条件,where sequenceTimeStamp=@lastTimeStamp
如果更新条数>0,则表示更新成功,如果失败,则继续读取sequence值,继续更新,直到更新成功为止。
优点:
1)没有lock和事务
2)速度比较快,运行了3年多无故障,故障率低
3)我还支持了自定义的编号,比如出库单,按年或月或日重新计数,比如订单。支付宝交易号等。
缺点:
可能一次无法成功,需要多次执行,直到取到Sequence的值
[解决办法]
用ticks 基本不会重复 除非时间有问题
[解决办法]
其实很简单,用一个同步加锁的方法,从1开始累加1就可以了,加锁是不可能重复的。
public synchronized static String getNo () {
return seq++;
}
[解决办法]
1. 直接使用数据库提供的Sequence (或者identity)
2. Java的话使用concurrent包中的AtomicLong类
或者自己写个synchronized方法
第一种麻烦点但是性能要比第二种好
[解决办法]
应对每个表设计一个编号规则,包括前后缀以及年月,领完要根据业务量决定流水号位数(如果单据号里包含了月,只要考虑一个月大约有多少单据),当然也可以对整个系统统一长度,比如都采取16位(XX201108-0001-XX)。当然其中的流水号要通过读取数据库最大单据号加1的方式。考虑你是多人使用,那么要在新增单据时获得一次,在保存时再获得一次避免冲突(因为中间有可能有人新增并保存过单据)。
避免重复的方式有多种,楼主该不会是问如何取得这种单据号的代码吧?