设计方案一:
使用redis的incr自增,由于redis是单线程的,每次按同一key自增可保证快速生成流水号,且唯一。
比如最基础的生成不重复序号:
long serilno=cacheClient.incr("CST");
incr操作在key为空时初始化为0
在实际意义中,客户号没有这种全0的。大部分可以是有部分含义的规则流水号。
比如:CST2018080200000
可考虑:CST+当天日期串+redis自增序号,其中以“CST”作为key值,后续00001调用字符串补充方法。
假设若要实现20180802从CST2018080200000生成,20180803也从CST2018080300000生成,则需要以CST+currentDate作为key值,其中currentDate字符串格式为yyyyMMdd,特别注意currentDate实际内容可能为20180802,而非“yyyyMMdd”。
附代码:
@Override
public String getSerialNumberByPrefix(String prefix) {
return getSerialNumberByRules(prefix,"yyMMddHHmmss",CrlSerialNumberCodeConstant.CRL_SERIAL_NUMBER_IDC,CrlSerialNumberCodeConstant.CRL_SERIAL_NUMBER_DATABASE,CrlSerialNumberCodeConstant.CRL_SERIAL_NUMBER_NORMAL,CrlSerialNumberCodeConstant.CRL_SERIAL_NUMBER_LENGTH);
}
@Override
public String getSerialNumberByPrefixAndLength(String prefix,int length) {
return getSerialNumberByRules(prefix,"yyMMddHHmmss",CrlSerialNumberCodeConstant.CRL_SERIAL_NUMBER_IDC,CrlSerialNumberCodeConstant.CRL_SERIAL_NUMBER_DATABASE,CrlSerialNumberCodeConstant.CRL_SERIAL_NUMBER_NORMAL,length);
}
/**
* @param prefix为业务前缀
* @param dateFormatter是日期格式
* @param normal是普通位
* @param length是流水号最后位数
*/
@Override
public String getSerialNumberByForFixedLength(String prefix,String dateFormatter,String idc,String dataBase,String normal,int length) {
String currentDate="";
if(StringUtils.isNotBlank(dateFormatter)){
currentDate=new SimpleDateFormat(dateFormatter).format(new Date());
}
StringBuilder crlSerialNumber=new StringBuilder();
try {
logger.info("getSerialNumberByPrefixAndLength|按业务前缀和后缀长度获取流水号|获取缓存值开始|prefix:" + prefix + "|length:" + length);
long cacheCurrentValue = cacheClient.incr(prefix +currentDate+length);
if(cacheCurrentValue==getMaxValueString(length)){
logger.info("getSerialNumberByPrefixAndLength|按业务前缀和后缀长度获取流水号|缓存达到位数最大值执行清除|prefix:" + prefix + "|length:" + length+"|cacheCurrentValue:"+cacheCurrentValue);
cacheClient.del(prefix +currentDate+ length);
}
String currentValue = getCurrentValueString(length, cacheCurrentValue);
return crlSerialNumber.append(prefix).append(currentDate).append(idc).append(dataBase).append(normal).append(currentValue).toString();
} catch (Exception e) {
logger.error("getSerialNumberByPrefixAndLength|按业务前缀和后缀长度获取流水号异常|prefix:"+prefix+"|length:"+length,"|exception", e);
int i=new Random().nextInt(getMaxValueString(length));
return crlSerialNumber.append(prefix).append(currentDate).append(idc).append(dataBase).append(String.valueOf(i)).toString();
}
}
/**
* 字符串补足方法
* @param length
* @param currentValue
* @return
*/
private String getCurrentValueString(int length, long currentValue) {
String cValue=String.valueOf(currentValue);
for(int i=cValue.length();i<length;i++){
cValue="0"+cValue;
}
return cValue;
}
/**
* 字符串最大值
* @param length
* @return
*/
private int getMaxValueString(int length) {
String value="";
for(int i=0;i<length;i++){
value="9"+value;
}
return Integer.parseInt(value);
}
附:
/*利用时间戳生成唯一序号的方法参考*/
public static final String str_yyyyMMddHHmmsssss = "yyyyMMddHHmmssSSS";
/**
* 将日期格式化为字符串
*
* @param date 日期
* @param pattern 格式
* @return 格式化后的日期串
*/
public static String date2Str(Date date, String pattern) {
SimpleDateFormat yyyy_MM_dd = new SimpleDateFormat(pattern);
return yyyy_MM_dd.format(date);
}