论坛首页 Java企业应用论坛

一个循环流水号实现,求评

浏览 13201 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (4)
作者 正文
   发表时间:2011-09-19   最后修改:2011-09-19
1.要可以设初始值
2.补0这种事交给Format 去作

'0' The result will be zero-padded

又好懂又没bug

3.现在spring这么流行,你用static这种方式有点土了。
0 请登录后投票
   发表时间:2011-09-19  
zuzong 写道
Crusader 写道
AnotherTomorrow 写道
hareamao 写道
方法的头一段可以改成:

        int n = ++serialNumber;
        serialNumber %= 999999;


另外,你的程序不考虑系统重启的可能性么?


小小纠正一下,按楼主要求,应该是
        int n = serialNumber = serialNumber%999999 + 1;

应该是可以不同步整个方法的吧,n属于局部变量,只要同步serialNumber部分就可以了。


有问题吧,这样一直加下去,不考虑int溢出吗?

整个操作过程 check - save - get 应该封装为原子操作,同时可以考虑使用jdk的原子变量类来简化过程


因为到了999999就设为0,重新计数,系统重启没考虑了,小弟又修改了下,恳请各位大哥指导啊~
public class SerialNumber {
	
	private static SerialNumber instance = new SerialNumber();
	
	public static SerialNumber getInstance(){
		return SerialNumber.instance;
	}
	
	private SystemParamDAO systemParamDAO;
	

	/**
	 * 流水号
	 */
	private static volatile int serialNumber = 0;
	
	/**
	 * 读取数据库中初始,或中断时记录的流水号
	 */
	public void initSerialNumber() {
		SerialNumber.serialNumber = Integer.parseInt(this.systemParamDAO.search("serial_number"));
	}
	
	/**
	 * 生成流水号
	 * 从1 - 999999,不足六位,从右往左补0
	 * @return
	 */
	public synchronized String generateSerialNumber(){
		int n = serialNumber = ++serialNumber;
		if(n == (999999 + 1)){
			serialNumber = n = 1;
		}
		
		SerialNumber.instance.systemParamDAO.updateBySerialNumber(n);
		
		StringBuffer strbu = new StringBuffer(6);
		strbu.append(n);
		for(int i=0, length=6-strbu.length(); i<length; i++){
			strbu.insert(0, 0);
		}
		
		return strbu.toString();
	}

	
	public void setSystemParamDAO(SystemParamDAO systemParamDAO) {
		this.systemParamDAO = systemParamDAO;
	}
	
}

这个貌似不是单利吧,没声明private的构造方法
0 请登录后投票
   发表时间:2011-09-19  
晕,刚才写了半天回复,一提交,居然不见了
0 请登录后投票
   发表时间:2011-09-19   最后修改:2011-09-19
感谢大家的回复,

我用的spring,systemParamDAO是注进来的,initSerialNumber方法也是在spring配置文件里设置的init-method

调用方是个helper类,原本那里是没有数据库操作的,但流水号又需要保存。。。想来想去,干脆把systemParamDAO当参数传进去吧,总归是要注入的,注入systemParamDAO,总比注入我这个流水号的好些

synchronized 是为了保证++serialNumber的计算

改成了这样
public class SerialNumber {
	
	private SystemParamDAO systemParamDAO;

	/**
	 * 流水号
	 */
	private static volatile int serialNumber = 0;
	
	/**
	 * 读取数据库中初始,或中断时记录的流水号
	 */
	public void initSerialNumber() {
		SerialNumber.serialNumber = Integer.parseInt(this.systemParamDAO.search("serial_number"));
	}
	
	/**
	 * 生成流水号
	 * 从1 - 999999,不足六位,从右往左补0
	 * @return
	 */
	public synchronized static String generateSerialNumber(SystemParamDAO systemParamDAO){
		int n = serialNumber = ++serialNumber;
		if(n == (999999 + 1)){
			serialNumber = n = 1;
		}
		
		systemParamDAO.updateBySerialNumber(n);
		
		StringBuilder strbu = new StringBuilder(6);
		strbu.append(n);
		for(int i=0, length=6-strbu.length(); i<length; i++){
			strbu.insert(0, 0);
		}
		
		return strbu.toString();
	}

	
	public void setSystemParamDAO(SystemParamDAO systemParamDAO) {
		this.systemParamDAO = systemParamDAO;
	}
	
}
0 请登录后投票
   发表时间:2011-09-19  
多线程下,试试AtomicLong呢...
0 请登录后投票
   发表时间:2011-09-19  
估计用的是MYSQL......
0 请登录后投票
   发表时间:2011-09-19  
调用参数里面还得传一个dao,这有点怪异吧
getNextSerialNumber不一定非得是static的

可以每次取下一个序列的时候都检查一下有没有初始化过,如果没有初始化,那么先从数据库读取数据进行初始化
如果已经初始化了,那么直接返回(内存中保存的数据+1)%LIMIT


 private static volatile boolean INITED = false;
    private static volatile int SN = 0;
    
    private void init(){
        SN = xxxDao.xx(); // 从数据库加载最后一次持久化的值
        INITED = true;
    }
    
    public synchronized String getNextSerialNumber(){
       if(!INITED) init(); 
       SN = (SN + 1) % LIMIT;
       // TODO: 更新数据库
       return String.format("%06d", SN);
    }
0 请登录后投票
   发表时间:2011-09-19   最后修改:2011-09-19
weiqiang.yang 写道
调用参数里面还得传一个dao,这有点怪异吧
getNextSerialNumber不一定非得是static的

可以每次取下一个序列的时候都检查一下有没有初始化过,如果没有初始化,那么先从数据库读取数据进行初始化
如果已经初始化了,那么直接返回(内存中保存的数据+1)%LIMIT


 private static volatile boolean INITED = false;
    private static volatile int SN = 0;
    
    private void init(){
        SN = xxxDao.xx(); // 从数据库加载最后一次持久化的值
        INITED = true;
    }
    
    public synchronized String getNextSerialNumber(){
       if(!INITED) init(); 
       SN = (SN + 1) % LIMIT;
       // TODO: 更新数据库
       return String.format("%06d", SN);
    }

如果再使用     
java.util.concurrent.atomic.AtomicLong
      long old =  SN.longvalue
      long new = (old+1)%LIMIT;

SN.weakCompareAndSet(old,new);
来作SN 就更加理想了,
去掉同步块大大增加多线程访问次数

最主要的是只看到业务逻辑
没看到丑陋的java底层代码

PS:为了好测试,可以把
if(!INITED) init();
放到spring的 initmethod里面去。
0 请登录后投票
   发表时间:2011-09-19  
最好从100000 开始,
0 请登录后投票
   发表时间:2011-09-19  
这系统重启不就恢复了嘛
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics