001/* 002 * Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.mybatisflex.core.keygen.impl; 017 018import com.mybatisflex.core.keygen.IKeyGenerator; 019 020import java.util.concurrent.ThreadLocalRandom; 021 022/** 023 * 独创的 FlexID 算法(简单、好用): 024 * <p> 025 * 特点: 026 * 1、保证 id 生成的顺序为时间顺序,越往后生成的 ID 值越大; 027 * 2、运行时,单台机器并发量在每秒钟 10w 以内; 028 * 3、运行时,无视时间回拨; 029 * 4、最大支持 99 台机器; 030 * 5、够用大概 300 年左右的时间; 031 * <p> 032 * 缺点: 033 * 1、每台机器允许最大的并发量为 10w/s。 034 * 2、出现时间回拨,重启机器时,在时间回拨未恢复的情况下,可能出现 id 重复。 035 * <p> 036 * ID组成:时间(7+)| 毫秒内的时间自增 (00~99:2)| 机器ID(00 ~ 99:2)| 随机数(00~99:2)用于分库分表时,通过 id 取模,保证分布均衡。 037 */ 038public class FlexIDKeyGenerator implements IKeyGenerator { 039 040 private static final long INITIAL_TIMESTAMP = 1680411660000L; 041 private static final long MAX_CLOCK_SEQ = 99; 042 043 private long lastTimeMillis = 0;//最后一次生成 ID 的时间 044 private long clockSeq = 0; //时间序列 045 private long workId = 1; //机器 ID 046 047 public FlexIDKeyGenerator() { 048 } 049 050 public FlexIDKeyGenerator(long workId) { 051 this.workId = workId; 052 } 053 054 @Override 055 public Object generate(Object entity, String keyColumn) { 056 return nextId(); 057 } 058 059 private synchronized long nextId() { 060 061 //当前时间 062 long currentTimeMillis = System.currentTimeMillis(); 063 064 if (currentTimeMillis == lastTimeMillis) { 065 clockSeq++; 066 if (clockSeq > MAX_CLOCK_SEQ) { 067 clockSeq = 0; 068 currentTimeMillis++; 069 } 070 } 071 072 //出现时间回拨 073 else if (currentTimeMillis < lastTimeMillis) { 074 currentTimeMillis = lastTimeMillis; 075 clockSeq++; 076 077 if (clockSeq > MAX_CLOCK_SEQ) { 078 clockSeq = 0; 079 currentTimeMillis++; 080 } 081 } else { 082 clockSeq = 0; 083 } 084 085 lastTimeMillis = currentTimeMillis; 086 087 long diffTimeMillis = currentTimeMillis - INITIAL_TIMESTAMP; 088 089 //ID组成:时间(7+)| 毫秒内的时间自增 (00~99:2)| 机器ID(00 ~ 99:2)| 随机数(00~99:2) 090 return diffTimeMillis * 1000000 + clockSeq * 10000 + workId * 100 + getRandomInt(); 091 } 092 093 094 private int getRandomInt() { 095 return ThreadLocalRandom.current().nextInt(100); 096 } 097 098 099}