package com.dy.common.util;
|
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.stereotype.Component;
|
|
import java.util.Calendar;
|
|
@Slf4j
|
@Component
|
public class IDLongGenerator {
|
|
private static final Object synObj = new Object() ;
|
|
private static final int yearLength = 4 ;//4:年度取四位, 3:年度取三位, 2:年度取两位, 1:年度取一位, 0:年度取0位
|
|
private static int add = 0 ;
|
private static final int chengShu = 1000 ;//1000:三位自增量,即一秒钟可产生10000个ID
|
private static final int maxAdd = 999 ;
|
private static long last;
|
//后缀
|
//在分布式系统中,例如多个数据中间件dataMw,多个系统都会向数据库中插入数据,用的都是此ID生成器,
|
//此ID生成器在各个子系统中难免为同一类数据生成相同的ID,造成数据库插入因主键相同而报错,
|
//所以设计此后缀,每个子系统后缀不同
|
private static int suffix = 0 ;
|
|
static {
|
last = current() ;
|
}
|
|
/**
|
* 2023 10 28 09 14 40 00000
|
* 长度19的ID,年度取两位,长度18的ID,年度取四位,17位数字超出了javascript的表数范围,javascript会表数不正确
|
*/
|
public Long generate(){
|
synchronized (synObj){
|
//Long id = doGenerate() ;
|
//log.info("产生ID = " + id);
|
//return id ;
|
return doGenerate() ;
|
}
|
}
|
/**
|
* 设置后缀,不同子系统设置不同的后缀
|
* @param suffix ID后缀,0到99
|
*/
|
public static void setSuffix(int suffix) throws Exception{
|
if(suffix < 0 || suffix > 99){
|
throw new Exception("后缀只能是0到99的数字") ;
|
}
|
IDLongGenerator.suffix = suffix ;
|
}
|
|
|
/**
|
* 得到今日开始的id(如: 230630 00000000000)
|
* @return ID
|
*/
|
public static Long generateTodayStartId(){
|
return (currentTodayStart() * chengShu) * 100 + suffix;
|
}
|
|
/**
|
* 得到今日截止的id(如: 230630 24000000000)
|
* @return ID
|
*/
|
public static Long generateTodayEndId(){
|
return (currentTodayEnd() * chengShu) * 100 + suffix;
|
}
|
|
|
/**
|
* 得到某日开始的id(如: 230630 00000000000)
|
* @return ID
|
*/
|
public static Long generateBeforeXDayStartId(int xday){
|
return (beforeXDayStart(xday) * chengShu) * 100 + suffix;
|
}
|
|
/**
|
* 得到某日截止的id(如: 230630 24000000000)
|
* @return ID
|
*/
|
public static Long generateBeforeXDayEndId(int xday){
|
return (beforeXDayEnd(xday) * chengShu) * 100 + suffix;
|
}
|
|
|
/**
|
* 得到某日开始的id(如: 230630 00000000000)
|
* @return ID
|
*/
|
public static Long generateOneDayStartId(int year, int month, int day){
|
return (currentOneDayStart(year, month, day) * chengShu) * 100 + suffix;
|
}
|
|
/**
|
* 得到某日截止的id(如: 230630 24000000000)
|
* @return ID
|
*/
|
public static Long generateOneDayEndId(int year, int month, int day){
|
return (currentOneDayEnd(year, month, day) * chengShu) * 100 + suffix;
|
}
|
|
|
|
/**
|
* 执行生成
|
* @return ID 20231218 104504 06900
|
*/
|
private Long doGenerate(){
|
long id ;
|
long now = current() ;
|
if(now != last){
|
//上次生成ID 与本次生成ID 不在同一秒内
|
last = now ;
|
add = 0 ;
|
id = last * chengShu + add++;
|
}else{
|
//上次生成ID 与本次生成ID 在同一秒内
|
if(add >= maxAdd){
|
//附加量已经用尽
|
waitNextSecond(last) ;//等到下一秒
|
id = last * chengShu + add++ ;//返回上一秒生成的ID
|
add = 0 ;//附加量归零,为下一秒准备
|
}else{
|
//附加量未用尽
|
id = last * chengShu + add++ ;
|
}
|
}
|
return (id * 100) + suffix ;
|
}
|
/**
|
* 等待下一秒到来
|
* @param last 上次时间(精确到秒)
|
*/
|
private void waitNextSecond(Long last){
|
try {
|
Thread.sleep(10);
|
} catch (InterruptedException ignored) {
|
}finally{
|
long now = current() ;
|
if(now == last){
|
waitNextSecond(last) ;
|
}
|
}
|
}
|
|
|
|
/**
|
* 格式为 y*yMMddHHmmss
|
* @return ID
|
*/
|
private static long current(){
|
Calendar cal = Calendar.getInstance();
|
return (dealYear(cal.get(Calendar.YEAR))) * 10000000000L
|
+ (cal.get(Calendar.MONTH) + 1) * 100000000L
|
+ cal.get(Calendar.DAY_OF_MONTH) * 1000000L
|
+ cal.get(Calendar.HOUR_OF_DAY) * 10000L
|
+ cal.get(Calendar.MINUTE) * 100L
|
+ cal.get(Calendar.SECOND) ;
|
}
|
|
|
/**
|
* 格式为
|
* @return ID
|
*/
|
private static long currentTodayStart(){
|
Calendar cal = Calendar.getInstance();
|
return (dealYear(cal.get(Calendar.YEAR))) * 10000000000L
|
+ (cal.get(Calendar.MONTH) + 1) * 100000000L
|
+ cal.get(Calendar.DAY_OF_MONTH) * 1000000L ;
|
}
|
|
/**
|
* 格式为
|
* @return ID
|
*/
|
private static long currentTodayEnd(){
|
Calendar cal = Calendar.getInstance();
|
return (dealYear(cal.get(Calendar.YEAR))) * 10000000000L
|
+ (cal.get(Calendar.MONTH) + 1) * 100000000L
|
+ cal.get(Calendar.DAY_OF_MONTH) * 1000000L
|
+ 24 * 10000L ;
|
}
|
|
|
/**
|
* 格式为
|
* @return ID
|
*/
|
private static long currentOneDayStart(int year, int month, int day){
|
return (dealYear(year)) * 10000000000L
|
+ month * 100000000L
|
+ day * 1000000L ;
|
}
|
|
/**
|
* 格式为
|
* @return ID
|
*/
|
private static long currentOneDayEnd(int year, int month, int day){
|
return (dealYear(year)) * 10000000000L
|
+ month * 100000000L
|
+ day * 1000000L
|
+ 24 * 10000L ;
|
}
|
|
/**
|
* 格式为
|
* @return ID
|
*/
|
private static long beforeXDayStart(int xday){
|
Calendar cal = Calendar.getInstance();
|
cal.add(Calendar.DATE, xday<=0?xday:-xday);
|
return (dealYear(cal.get(Calendar.YEAR))) * 10000000000L
|
+ (cal.get(Calendar.MONTH) + 1) * 100000000L
|
+ cal.get(Calendar.DAY_OF_MONTH) * 1000000L ;
|
}
|
|
/**
|
* 格式为
|
* @return ID
|
*/
|
private static long beforeXDayEnd(int xday){
|
Calendar cal = Calendar.getInstance();
|
cal.add(Calendar.DATE, xday<=0?xday:-xday);
|
return (dealYear(cal.get(Calendar.YEAR))) * 10000000000L
|
+ (cal.get(Calendar.MONTH) + 1) * 100000000L
|
+ cal.get(Calendar.DAY_OF_MONTH) * 1000000L
|
+ 24 * 10000L ;
|
}
|
|
/**
|
* 处理年度
|
* @param year 年度
|
* @return 处理后的年度
|
*/
|
private static int dealYear(int year){
|
if(yearLength == 0){
|
return 0 ;
|
}else if(yearLength == 1){
|
return year % 10 ;
|
}else if(yearLength == 2){
|
return year % 100 ;
|
}else if(yearLength == 3){
|
return year % 1000 ;
|
}else if(yearLength == 4){
|
return year ;
|
}else{
|
return year ;
|
}
|
}
|
|
// public static void main(String[] args){
|
// Calendar cal = Calendar.getInstance();
|
// System.out.println(cal.get(Calendar.MONTH) + 1) ;
|
//
|
// IDLongGenerator o = new IDLongGenerator() ;
|
// int total = 1 ;
|
// for(int i = 0 ; i < total ; i++){
|
// System.out.println(o.generate()) ;
|
// }
|
// long start = System.currentTimeMillis() ;
|
// long end = System.currentTimeMillis() ;
|
// System.out.println("产生" + total + "ID用时" + (end - start) + "毫秒");
|
//
|
// Long todayStartId = IDLongGenerator.generateTodayStartId() ;
|
// System.out.println("today start id:\n" + todayStartId);
|
// Long todayEndId = IDLongGenerator.generateTodayEndId() ;
|
// System.out.println("today end id:\n" + todayEndId);
|
//
|
//
|
// Long beforeXDayStartId = IDLongGenerator.generateBeforeXDayStartId(3) ;
|
// System.out.println("before3Day start id:\n" + beforeXDayStartId);
|
// Long beforeXDayEndId = IDLongGenerator.generateBeforeXDayEndId(3) ;
|
// System.out.println("before3Day end id:\n" + beforeXDayEndId);
|
//
|
//
|
// Long oneDayStartId = IDLongGenerator.generateOneDayStartId(2023, 7, 9) ;
|
// System.out.println("OneDay(2023-07-09) start id:\n" + oneDayStartId);
|
// Long oneDayEndId = IDLongGenerator.generateOneDayEndId(2023, 7, 11) ;
|
// System.out.println("OneDay(2023-07-11) end id:\n" + oneDayEndId);
|
// }
|
|
}
|