mybatis-plus雪花算法自動生成機器id原理及源碼
1、雪花算法原理
雪花算法使用一個 64 bit 的 long 型的數(shù)字作為全局唯一 id。這 64 個 bit 中,其中 1 個 bit 是不用的,然后用其中的 41 bit 作為毫秒數(shù),用 10 bit 作為工作機器 id,12 bit 作為序列號。

- 1bit,不用,因為二進制中最高位是符號位,1表示負數(shù),0表示正數(shù)。生成的id一般都是用整數(shù),所以最高位固定為0。
- 41bit-時間戳,用來記錄時間戳,毫秒級。
- 10bit-工作機器id,用來記錄工作機器id。
- 12bit-序列號,序列號,用來記錄同毫秒內(nèi)產(chǎn)生的不同id。即可以用0、1、2、3、…4094這4095個數(shù)字,來表示同一機器同一時間截(毫秒)內(nèi)產(chǎn)生的4095個ID序號。
SnowFlake可以保證:
所有生成的id按時間趨勢遞增
整個分布式系統(tǒng)內(nèi)不會產(chǎn)生重復(fù)id(因為有datacenterId和workerId來做區(qū)分)
如上大概了解了雪花算法的原理,而且也知道機器號對于雪花算法的重要性。如果機器號一樣,可能會出現(xiàn)id重復(fù)的情況。
mybatis-plus自3.3.0開始,默認使用雪花算法+UUID(不含中劃線),但是它并沒有強制讓開發(fā)者配置機器號。這一點很是疑惑,這樣可能會讓不了解雪花算法的人埋下了一個坑。
但是這么強大的一個框架難道真的沒有做優(yōu)化嗎?帶著問題,查看了下mybatis-plus雪花算法源碼com.baomidou.mybatisplus.core.toolkit.Sequence。最終發(fā)現(xiàn)在沒有設(shè)置機器號的情況下,會通過當前物理網(wǎng)卡地址和jvm的進程ID自動生成。這真的是一個較好的解決方案。一般在一個集群中,MAC+JVM進程PID一樣的幾率非常小。
2、自動生成唯一機器號源碼
核心代碼。有兩個構(gòu)造方法,一個無參構(gòu)造,一個有參構(gòu)造。
public Sequence() {
//通過當前物理網(wǎng)卡地址獲取datacenterId
this.datacenterId = getDatacenterId(maxDatacenterId);
//物理網(wǎng)卡地址+jvm進程pi獲取workerId
this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
}
/**
* 有參構(gòu)造器
*
* @param workerId 工作機器 ID
* @param datacenterId 序列號
*/
public Sequence(long workerId, long datacenterId) {
Assert.isFalse(workerId > maxWorkerId || workerId < 0,
String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
Assert.isFalse(datacenterId > maxDatacenterId || datacenterId < 0,
String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
this.workerId = workerId;
this.datacenterId = datacenterId;
}
- 無參構(gòu)造 開發(fā)者沒有設(shè)置機器號時
- 有參構(gòu)造 開發(fā)者自行設(shè)置機器號
protected static long getDatacenterId(long maxDatacenterId) {
long id = 0L;
try {
//獲取本機(或者服務(wù)器ip地址)
//DESKTOP-123SDAD/192.168.1.87
InetAddress ip = InetAddress.getLocalHost();
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
//一般不是null會進入else
if (network == null) {
id = 1L;
} else {
//獲取物理網(wǎng)卡地址
byte[] mac = network.getHardwareAddress();
if (null != mac) {
id = ((0x000000FF & (long) mac[mac.length - 2]) | (0x0000FF00 & (((long) mac[mac.length - 1]) << 8))) >> 6;
id = id % (maxDatacenterId + 1);
}
}
} catch (Exception e) {
logger.warn(" getDatacenterId: " + e.getMessage());
}
return id;
}
/**
* 獲取 maxWorkerId
*/
protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
StringBuilder mpid = new StringBuilder();
mpid.append(datacenterId);
//獲取jvm進程信息
String name = ManagementFactory.getRuntimeMXBean().getName();
if (StringUtils.isNotBlank(name)) {
/*
* 獲取進程PID
*/
mpid.append(name.split(StringPool.AT)[0]);
}
/*
* MAC + PID 的 hashcode 獲取16個低位
*/
return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
}
以上就是mybatis-plus雪花算法自動生成機器id原理的詳細內(nèi)容,更多關(guān)于mybatis plus雪花id的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
IDEA啟動Springboot報錯:無效的目標發(fā)行版:17 的解決辦法
這篇文章主要給大家介紹了IDEA啟動Springboot報錯:無效的目標發(fā)行版:17 的解決辦法,文中通過代碼示例和圖文講解的非常詳細,對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-02-02
SpringBoot中動態(tài)數(shù)據(jù)源配置與使用詳解
在現(xiàn)代應(yīng)用中,處理多數(shù)據(jù)源是常見的需求,在 Spring Boot 中,這樣的需求可以通過動態(tài)數(shù)據(jù)源來輕松實現(xiàn),本篇博客將詳細介紹如何在 Spring Boot 中配置和使用動態(tài)數(shù)據(jù)源,并演示如何切換到指定的數(shù)據(jù)源,需要的朋友可以參考下2024-10-10
項目打包成jar后包無法讀取src/main/resources下文件的解決
本文主要介紹了項目打包成jar后包無法讀取src/main/resources下文件的解決,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04

