This commit is contained in:
oneao committed 2025-06-11 09:33:24 +08:00
1 parent a4827cb646
commit 5c0ab2ce7d
3 files changed
+64 -122

No files matched your search

@@ -12,7 +12,6 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
})
public class BaseApplication {
public static void main(String[] args) {
System.out.println(SnowflakeIdUtils.nextId());
SpringApplication.run(BaseApplication.class,args);
}
}
@@ -13,153 +13,85 @@ import java.util.concurrent.TimeUnit;
@Slf4j
public class SnowflakeIdUtils {
public static long MAX_START_INTERVAL_TIME = TimeUnit.SECONDS.toNanos(5L);
private static final long twepoch = 1288834974657L;
// 起始时间戳(建议设置为项目上线时间)
private static final long START_TIMESTAMP = 1288834974657L;
private static final long workerIdBits = 5L;
private static final long datacenterIdBits = 5L;
private static final long maxWorkerId = 31L;
private static final long maxDatacenterId = 31L;
private static final long sequenceBits = 12L;
// 各部分位数
private static final long SEQUENCE_BITS = 12L;
private static final long MACHINE_BITS = 5L;
private static final long DATACENTER_BITS = 5L;
private static final long workerIdShift = 12L;
private static final long datacenterIdShift = 17L;
private static final long timestampLeftShift = 22L;
private static final long sequenceMask = 4095L;
// 最大值
private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);
private static final long MAX_MACHINE_ID = ~(-1L << MACHINE_BITS);
private static final long MAX_DATACENTER_ID = ~(-1L << DATACENTER_BITS);
// 这两个必须初始化
private static long workerId;
// 左移位数
private static final long MACHINE_LEFT = SEQUENCE_BITS;
private static final long DATACENTER_LEFT = SEQUENCE_BITS + MACHINE_BITS;
private static final long TIMESTAMP_LEFT = SEQUENCE_BITS + MACHINE_BITS + DATACENTER_BITS;
// 参数及状态(静态)
private static long datacenterId;
private static long machineId;
private static long sequence = 0L;
private static long lastTimestamp = -1L;
private static boolean initialized = false;
private static InetAddress inetAddress;
// 初始化一次即可,线程安全调用
public static synchronized void init(InetAddress address) {
if (inetAddress == null) {
inetAddress = address;
datacenterId = getDatacenterId(maxDatacenterId);
workerId = getMaxWorkerId(datacenterId, maxWorkerId);
long start = System.nanoTime();
long end = System.nanoTime();
if (end - start > MAX_START_INTERVAL_TIME) {
log.warn("Initialization Sequence Very Slow! Get datacenterId:{} workerId:{}", datacenterId, workerId);
} else {
initLog();
}
// 初始化方法(只能调用一次)
public static synchronized void init(long dcId, long mId) {
if (initialized) {
throw new IllegalStateException("SnowflakeIdGenerator has already been initialized.");
}
}
public static synchronized void init(long fixedWorkerId, long fixedDatacenterId) {
Assert.isTrue(fixedWorkerId <= maxWorkerId && fixedWorkerId >= 0,
String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
Assert.isTrue(fixedDatacenterId <= maxDatacenterId && fixedDatacenterId >= 0,
String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
workerId = fixedWorkerId;
datacenterId = fixedDatacenterId;
initLog();
}
private static void initLog() {
if (log.isDebugEnabled()) {
log.debug("Initialization Sequence datacenterId:{} workerId:{}", datacenterId, workerId);
if (dcId > MAX_DATACENTER_ID || dcId < 0) {
throw new IllegalArgumentException("datacenterId must be between 0 and " + MAX_DATACENTER_ID);
}
}
protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
StringBuilder mpid = new StringBuilder();
mpid.append(datacenterId);
String name = ManagementFactory.getRuntimeMXBean().getName();
if (StringUtils.isNotBlank(name)) {
mpid.append(name.split("@")[0]);
if (mId > MAX_MACHINE_ID || mId < 0) {
throw new IllegalArgumentException("machineId must be between 0 and " + MAX_MACHINE_ID);
}
return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1L);
}
protected static long getDatacenterId(long maxDatacenterId) {
long id = 0L;
try {
if (inetAddress == null) {
if (log.isDebugEnabled()) {
log.debug("Use localhost address");
}
inetAddress = InetAddress.getLocalHost();
}
if (log.isDebugEnabled()) {
log.debug("Get {} network interface", inetAddress);
}
NetworkInterface network = NetworkInterface.getByInetAddress(inetAddress);
if (log.isDebugEnabled()) {
log.debug("Get network interface info: {}", network);
}
if (network == null) {
log.warn("Unable to get network interface for {}", inetAddress);
id = 1L;
} else {
byte[] mac = network.getHardwareAddress();
if (mac != null && mac.length >= 2) {
id = ((0xffL & (long) mac[mac.length - 2]) | (0xff00L & ((long) mac[mac.length - 1] << 8))) >> 6;
id %= maxDatacenterId + 1L;
}
}
} catch (Exception e) {
log.warn("getDatacenterId error: {}", e.getMessage(), e);
}
return id;
datacenterId = dcId;
machineId = mId;
initialized = true;
}
// 生成 ID(线程安全)
public static synchronized long nextId() {
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
long offset = lastTimestamp - timestamp;
if (offset > 5L) {
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", offset));
}
try {
SnowflakeIdUtils.class.wait(offset << 1);
timestamp = timeGen();
if (timestamp < lastTimestamp) {
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", offset));
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (!initialized) {
throw new IllegalStateException("SnowflakeIdGenerator not initialized. Call init() first.");
}
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask;
long currentTimestamp = timeGen();
if (currentTimestamp < lastTimestamp) {
throw new RuntimeException("Clock moved backwards. Refusing to generate id.");
}
if (currentTimestamp == lastTimestamp) {
sequence = (sequence + 1) & MAX_SEQUENCE;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
currentTimestamp = waitNextMillis(currentTimestamp);
}
} else {
sequence = ThreadLocalRandom.current().nextLong(1, 3);
sequence = 0L;
}
lastTimestamp = timestamp;
lastTimestamp = currentTimestamp;
return ((timestamp - twepoch) << timestampLeftShift)
| (datacenterId << datacenterIdShift)
| (workerId << workerIdShift)
return ((currentTimestamp - START_TIMESTAMP) << TIMESTAMP_LEFT)
| (datacenterId << DATACENTER_LEFT)
| (machineId << MACHINE_LEFT)
| sequence;
}
protected static long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
private static long waitNextMillis(long currentTimestamp) {
while (currentTimestamp <= lastTimestamp) {
currentTimestamp = timeGen();
}
return timestamp;
return currentTimestamp;
}
protected static long timeGen() {
private static long timeGen() {
return System.currentTimeMillis();
}
public static long parseIdTimestamp(long id) {
return (id >> 22) + 1288834974657L;
}
}
@@ -1,11 +1,22 @@
#datasource:
# db1:
# url: jdbc:jtds:sqlserver://127.0.0.1:1433;databaseName=test1
# username: sa
# password: sa
# driverClassName: net.sourceforge.jtds.jdbc.Driver
# db2:
# url: jdbc:jtds:sqlserver://127.0.0.1:1433;databaseName=test2
# username: sa
# password: sa
# driverClassName: net.sourceforge.jtds.jdbc.Driver
datasource:
db1:
url: jdbc:jtds:sqlserver://127.0.0.1:1433;databaseName=test1
url: jdbc:jtds:sqlserver://192.168.1.176:1433;databaseName=G3-Email
username: sa
password: sa
driverClassName: net.sourceforge.jtds.jdbc.Driver
db2:
url: jdbc:jtds:sqlserver://127.0.0.1:1433;databaseName=test2
url: jdbc:jtds:sqlserver://192.168.1.176:1433;databaseName=G3-Website
username: sa
password: sa
driverClassName: net.sourceforge.jtds.jdbc.Driver