New file |
| | |
| | | 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 ; |
| | | private static final int noSuffix = 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 + noSuffix; |
| | | } |
| | | |
| | | /** |
| | | * 得到今日截止的id(如: 230630 24000000000) |
| | | * @return ID |
| | | */ |
| | | public static Long generateTodayEndId(){ |
| | | return (currentTodayEnd() * chengShu) * 100 + noSuffix; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 得到某日开始的id(如: 230630 00000000000) |
| | | * @return ID |
| | | */ |
| | | public static Long generateBeforeXDayStartId(int xday){ |
| | | return (beforeXDayStart(xday) * chengShu) * 100 + noSuffix; |
| | | } |
| | | |
| | | /** |
| | | * 得到某日截止的id(如: 230630 24000000000) |
| | | * @return ID |
| | | */ |
| | | public static Long generateBeforeXDayEndId(int xday){ |
| | | return (beforeXDayEnd(xday) * chengShu) * 100 + noSuffix; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 得到某日开始的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); |
| | | // } |
| | | |
| | | } |