您好,欢迎访问一九零五行业门户网

Java之流水号生成器

提出问题
如何使用java生成流水号,同时支持可配置和高并发?
解决问题
假设你们项目已经整合缓存技术
假如你有一定的java基础
假如……
下面的代码实现的是一个支持高并发,可配置,效率高的流水号生成器,可同时为一个项目的多个模块使用,流水号支持缓存,即每次会预先生成一定数量的流水号存放在缓存中,需要的时候,优先到缓存中去,缓存中的序列号使用完之后,重新生成一定数量的流水号放到缓存中,如此循环,提高效率……
同时,该流水号生成器是线程安全的,使用线程锁进行保护,已经真正的投入到项目中使用……
数据库表设计
[code]create table sys_serial_number2 ( "id" varchar(32) collate "default" not null, "module_name" varchar(50) collate "default", "module_code" varchar(50) collate "default", "config_templet" varchar(50) collate "default", "max_serial" varchar(32) collate "default", "pre_max_num" varchar(32) collate "default", "is_auto_increment" char(1) collate "default" )
说明:
[code]module_name:模块名称 module_code:模块编码 config_templet:当前模块 使用的序列号模板 max_serial:存放当前序列号的值 pre_max_num:预生成序列号存放到缓存的个数 is_auto_increment:是否自动增长模式,0:否 1:是
注意:目前序列号模板只支持字母,动态数字(0000 代表1-9999),和日期用${date}的组合形式
is_auto_increment配置为1 ,这时配置模板为cx000000生成的序列号为:cx1 ,cx2,cx3…..
配置为0,这时配置模板为cx0000000生成的序列号为:cx00000001,cx00000002,cx00000003
数据库配置说明:如需要项目模块的项目编号,则需要在数据库表sys_serial_number中配置一条记录:
[code]| id | module_name | module_code | config_templet | max_serial | pre_max_num | is_auto_increment |-------|--------------|--------------|-----------------|-------------|-------------|--------------------/ | xxxx | 项目 | pj |cx00000000${date}| 2650 | 100 | 1
cx00000000${date}生成的序列号类似于:cx0000000120160522 ,cx0000000220160522,cx0000000320160522 ……
序列号model实体设计:
[code]package com.evada.de.serialnum.model; import com.evada.de.common.model.basemodel; import javax.persistence.column; import javax.persistence.entity; import javax.persistence.table; /** * 功能描述:序列号表模型 * * @author :ay 2015/11/23 */ @entity @table(name="sys_serial_number") public class systemserialnumber extends basemodel { /** * 模块名称 */ @column(name = "module_name", columndefinition = "varchar") private string modulename; /** * 模块编码 */ @column(name = "module_code", columndefinition = "varchar") private string modulecode; /** * 流水号配置模板 */ @column(name = "config_templet", columndefinition = "varchar") private string configtemplet; /** * 序列号最大值 */ @column(name = "max_serial", columndefinition = "varchar") private string maxserial; /** * 是否自动增长标示 */ @column(name = "is_auto_increment", columndefinition = "varchar") private string isautoincrement; public string getisautoincrement() { return isautoincrement; } public void setisautoincrement(string isautoincrement) { this.isautoincrement = isautoincrement; } /** * 预生成流水号数量 */ @column(name = "pre_max_num", columndefinition = "varchar") private string premaxnum; public string getpremaxnum() { return premaxnum; } public void setpremaxnum(string premaxnum) { this.premaxnum = premaxnum; } public string getmodulename() { return modulename; } public void setmodulename(string modulename) { this.modulename = modulename; } public string getmodulecode() { return modulecode; } public void setmodulecode(string modulecode) { this.modulecode = modulecode; } public string getconfigtemplet() { return configtemplet; } public void setconfigtemplet(string configtemplet) { this.configtemplet = configtemplet; } public string getmaxserial() { return maxserial; } public void setmaxserial(string maxserial) { this.maxserial = maxserial; } public systemserialnumber(string id){ this.id = id; } public systemserialnumber(string id,string modulecode){ this.id = id; this.modulecode = modulecode; } public systemserialnumber(){} }
service接口设计:
[code]package com.evada.de.serialnum.service; import com.evada.de.serialnum.dto.systemserialnumberdto; /** * 序列号service接口 * created by huangwy on 2015/11/24. */ public interface iserialnumservice { public systemserialnumberdto find(systemserialnumberdto systemserialnumberdto); public string generateserialnumberbymodelcode(string modulecode); /** * 设置最小值 * @param value 最小值,要求:大于等于零 * @return 流水号生成器实例 */ iserialnumservice setmin(int value); /** * 设置最大值 * @param value 最大值,要求:小于等于long.max_value ( 9223372036854775807 ) * @return 流水号生成器实例 */ iserialnumservice setmax(long value); /** * 设置预生成流水号数量 * @param count 预生成数量 * @return 流水号生成器实例 */ iserialnumservice setprepare(int count); }
service实现:
[code]package com.evada.de.serialnum.service.impl; import com.evada.de.common.constants.serialnumconstants; import com.evada.de.serialnum.dto.systemserialnumberdto; import com.evada.de.serialnum.model.systemserialnumber; import com.evada.de.serialnum.repository.serialnumberrepository; import com.evada.de.serialnum.repository.mybatis.serialnumberdao; import com.evada.de.serialnum.service.iserialnumservice; import com.evada.inno.common.util.beanutils; import com.evada.inno.common.util.dateutils; import org.slf4j.logger; import org.slf4j.loggerfactory; import org.springframework.beans.factory.annotation.autowired; import org.springframework.cache.annotation.cacheput; import org.springframework.stereotype.service; import java.text.decimalformat; import java.util.*; import java.util.concurrent.locks.reentrantlock; /** * created by ay on 2015/11/24. */ @service("serialnumberservice") public class serialnumberserviceimpl implements iserialnumservice { private static final logger logger = loggerfactory.getlogger(serialnumberserviceimpl.class); @autowired private serialnumberdao serialnumberdao; @autowired private serialnumberrepository serialnumberrepository; /** 格式 */ private string pattern = ""; /** 生成器锁 */ private final reentrantlock lock = new reentrantlock(); /** 流水号格式化器 */ private decimalformat format = null; /** 预生成锁 */ private final reentrantlock preparelock = new reentrantlock(); /** 最小值 */ private int min = 0; /** 最大值 */ private long max = 0; /** 已生成流水号(种子) */ private long seed = min; /** 预生成数量 */ private int prepare = 0; /** 数据库存储的当前最大序列号 **/ long maxserialint = 0; /** 当前序列号是否为个位数自增的模式 **/ private string isautoincrement = "0"; systemserialnumberdto systemserialnumberdto = new systemserialnumberdto(); /** 预生成流水号 */ hashmap<string,list<string>> prepareserialnumbermap = new hashmap<>(); /** * 查询单条序列号配置信息 * @param systemserialnumberdto * @return */ @override public systemserialnumberdto find(systemserialnumberdto systemserialnumberdto) { return serialnumberdao.find(systemserialnumberdto); } /** * 根据模块code生成预数量的序列号存放到map中 * @param modulecode 模块code * @return */ @cacheput(value = "serialnumber",key="#modulecode") public list<string> generateprepareserialnumbers(string modulecode){ //临时list变量 list<string> resultlist = new arraylist<string>(prepare); lock.lock(); try{ for(int i=0;i<prepare;i++){ maxserialint = maxserialint + 1; if(maxserialint > min && (maxserialint + "").length() < max ){ seed = maxserialint ; }else{ //如果动态数字长度大于模板中的长度 例:模板cf000 maxserialint 1000 seed = maxserialint = 0; //更新数据,重置maxserialint为0 systemserialnumberdto.setmaxserial("0"); systemserialnumber systemserialnumber = new systemserialnumber(); beanutils.copyproperties(systemserialnumber,systemserialnumberdto); serialnumberrepository.save(systemserialnumber); } //动态数字生成 string formatserialnum = format.format(seed); //动态日期的生成 if(pattern.contains(serialnumconstants.date_symbol)){ string currentdate = dateutils.format(new date(),"yyyymmdd"); formatserialnum = formatserialnum.replace(serialnumconstants.date_symbol,currentdate); } resultlist.add(formatserialnum); } //更新数据 systemserialnumberdto.setmaxserial(maxserialint + ""); systemserialnumber systemserialnumber = new systemserialnumber(); beanutils.copyproperties(systemserialnumber,systemserialnumberdto); serialnumberrepository.save(systemserialnumber); }finally{ lock.unlock(); } return resultlist; } /** * 根据模块code生成序列号 * @param modulecode 模块code * @return 序列号 */ public string generateserialnumberbymodelcode(string modulecode){ //预序列号加锁 preparelock.lock(); try{ //判断内存中是否还有序列号 if(null != prepareserialnumbermap.get(modulecode) && prepareserialnumbermap.get(modulecode).size() > 0){ //若有,返回第一个,并删除 return prepareserialnumbermap.get(modulecode).remove(0); } }finally { //预序列号解锁 preparelock.unlock(); } systemserialnumberdto = new systemserialnumberdto(); systemserialnumberdto.setmodulecode(modulecode); systemserialnumberdto = serialnumberdao.find(systemserialnumberdto); prepare = integer.parseint(systemserialnumberdto.getpremaxnum().trim());//预生成流水号数量 pattern = systemserialnumberdto.getconfigtemplet().trim();//配置模板 string maxserial = systemserialnumberdto.getmaxserial().trim(); //存储当前最大值 isautoincrement = systemserialnumberdto.getisautoincrement().trim(); maxserialint = long.parselong(maxserial.trim());//数据库存储的最大序列号 max = this.counter(pattern,'0') + 1;//根据模板判断当前序列号数字的最大值 if(isautoincrement.equals("1")){ pattern = pattern.replace("0","#"); } format = new decimalformat(pattern); //生成预序列号,存到缓存中 list<string> resultlist = generateprepareserialnumbers(modulecode); preparelock.lock(); try { prepareserialnumbermap.put(modulecode, resultlist); return prepareserialnumbermap.get(modulecode).remove(0); } finally { preparelock.unlock(); } } /** * 设置最小值 * * @param value 最小值,要求:大于等于零 * @return 流水号生成器实例 */ public iserialnumservice setmin(int value) { lock.lock(); try { this.min = value; }finally { lock.unlock(); } return this; } /** * 最大值 * * @param value 最大值,要求:小于等于long.max_value ( 9223372036854775807 ) * @return 流水号生成器实例 */ public iserialnumservice setmax(long value) { lock.lock(); try { this.max = value; }finally { lock.unlock(); } return this; } /** * 设置预生成流水号数量 * @param count 预生成数量 * @return 流水号生成器实例 */ public iserialnumservice setprepare(int count) { lock.lock(); try { this.prepare = count; }finally { lock.unlock(); } return this; } /** * 统计某一个字符出现的次数 * @param str 查找的字符 * @param c * @return */ private int counter(string str,char c){ int count=0; for(int i = 0;i < str.length();i++){ if(str.charat(i)==c){ count++; } } return count; } }
以上就是java之流水号生成器的内容。
其它类似信息

推荐信息