MyBatis-Plus 內置雪花算法主鍵重復問題
點擊關注上方“Stephen”,
設為“置頂或星標”,第一時間送達干貨
問題描述
目前項目使用的id是mybatis-plus 內置的主鍵生成策略 ID_WORKER ,最近測試在做性能壓測,部署架構是單服務集群的部署方式,然后就發(fā)現了id重復的異常,異常如下
問題分析
首先分析的是id生成是不是就是重復了,先關掉其中一臺機器,單機跑,這個時候發(fā)現壓到1000的并發(fā)都沒有出現過id重復,這個說明單機情況下不存在id重復問題,說明只有集群的情況下才會出現。
再分析一下id生成的幾個要素,雪花算法的核心能影響到id生成的幾個因素:
-
服務器時間 -
workId(機器 ID 部分) -
datacenterId(數據標識 ID 部分)。
先檢查了一下服務器時間,都是一樣的,然后再看一下workId的生成,我們先看一下源碼。
public Sequence() {
this.datacenterId = getDatacenterId(maxDatacenterId);
this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
}
//獲取workerId
protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
StringBuilder mpid = new StringBuilder();
mpid.append(datacenterId);
//代表正在運行的Java虛擬機的名稱。
String name = ManagementFactory.getRuntimeMXBean().getName();
if (StringUtils.isNotEmpty(name)) {
/*
* GET jvmPid
*/
mpid.append(name.split(StringPool.AT)[0]);
}
/*
* MAC + PID 的 hashcode 獲取16個低位
*/
return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
}
這里生成的workerId主要核心影響就是獲取運行的虛擬機名稱,現在猜測就是有可能是由于兩臺機的虛擬機名稱可能一樣,導致拿到的workerId一樣。這個沒有具體去驗證,猜測是這樣的。那我們嘗試修改一下這個workerId的值。
問題解決
1.先設置workerId為隨機數,這樣保證每個機器部署的時候拿到的都是隨機數
# 設置隨機
mybatis-plus.global-config.worker-id: ${random.int}
這里你啟動項目的時候回發(fā)現一個異常
異常很明顯,這里的worer id 必選小于31,那我們就需要修改一下隨機數
# 設置隨機
mybatis-plus.global-config.worker-id: ${random.int(1,31)}
這個時候我們先看一下我們設置參數有沒有生效,為了比較明顯看到效果,我們直接設置worker-id為一個固定值20,再斷點看一下,我們找到com.baomidou.mybatisplus.core.toolkit.IdWorker這個核心類,獲取id的核心方法是com.baomidou.mybatisplus.core.toolkit.IdWorker#getId,那我們就在這里加一個斷點看下
public class IdWorker {
/**
* 主機和進程的機器碼
*/
private static Sequence WORKER = new Sequence();
//獲取id
public static long getId() {
return WORKER.nextId();
}
public static String getIdStr() {
return String.valueOf(WORKER.nextId());
}
/**
* <p>
* 有參構造器
* </p>
*
* @param workerId 工作機器 ID
* @param datacenterId 序列號
*/
public static void initSequence(long workerId, long datacenterId) {
WORKER = new Sequence(workerId, datacenterId);
}
/**
* <p>
* 使用ThreadLocalRandom獲取UUID獲取更優(yōu)的效果 去掉"-"
* </p>
*/
public static String get32UUID() {
ThreadLocalRandom random = ThreadLocalRandom.current();
return new UUID(random.nextLong(), random.nextLong()).toString().replace(StringPool.DASH, StringPool.EMPTY);
}
}
斷點后的結果是:
這個時候看到workerId沒有生效,我們繼續(xù)分析下源碼。
項目啟動的時候,mybatis-plus 會調用一個com.baomidou.mybatisplus.core.MybatisConfiguration#init方法來初始化配置信息,我們看下代碼
public void init(GlobalConfig globalConfig) {
// 初始化 Sequence
//這里需要同時設置workerId和datacenterId
if (null != globalConfig.getWorkerId()
&& null != globalConfig.getDatacenterId()) {
IdWorker.initSequence(globalConfig.getWorkerId(), globalConfig.getDatacenterId());
}
// 打印 Banner
if (globalConfig.isBanner()) {
System.out.println(" _ _ |_ _ _|_. ___ _ | _ ");
System.out.println("| | |\\/|_)(_| | |_\\ |_)||_|_\\ ");
System.out.println(" / | ");
System.out.println(" "+MybatisPlusVersion.getVersion()+" ");
}
}
我們發(fā)現workerId和datacenterId必須同時設置才會獲取我們設置的值。
那我們就修改配置一下
# 設置隨機
mybatis-plus.global-config.worker-id: ${random.int(1,31)}
mybatis-plus.global-config.datacenter-id: ${random.int(1,31)}
這樣設置以后發(fā)現終于生效了,然后部署一下,問題終于解決了。這里問題雖然解決了,但是workerId重復其實沒有實際驗證過,如果有驗證過的同學歡迎留言。
來源:blog.csdn.net/wagnteng/
article/details/117064242
問題描述
目前項目使用的id是mybatis-plus 內置的主鍵生成策略 ID_WORKER ,最近測試在做性能壓測,部署架構是單服務集群的部署方式,然后就發(fā)現了id重復的異常,異常如下
問題分析
首先分析的是id生成是不是就是重復了,先關掉其中一臺機器,單機跑,這個時候發(fā)現壓到1000的并發(fā)都沒有出現過id重復,這個說明單機情況下不存在id重復問題,說明只有集群的情況下才會出現。
再分析一下id生成的幾個要素,雪花算法的核心能影響到id生成的幾個因素:
-
服務器時間
-
workId(機器 ID 部分)
-
datacenterId(數據標識 ID 部分)。
先檢查了一下服務器時間,都是一樣的,然后再看一下workId的生成,我們先看一下源碼。
public Sequence() {
this.datacenterId = getDatacenterId(maxDatacenterId);
this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
}
//獲取workerId
protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
StringBuilder mpid = new StringBuilder();
mpid.append(datacenterId);
//代表正在運行的Java虛擬機的名稱。
String name = ManagementFactory.getRuntimeMXBean().getName();
if (StringUtils.isNotEmpty(name)) {
/*
* GET jvmPid
*/
mpid.append(name.split(StringPool.AT)[0]);
}
/*
* MAC + PID 的 hashcode 獲取16個低位
*/
return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
}
這里生成的workerId主要核心影響就是獲取運行的虛擬機名稱,現在猜測就是有可能是由于兩臺機的虛擬機名稱可能一樣,導致拿到的workerId一樣。這個沒有具體去驗證,猜測是這樣的。那我們嘗試修改一下這個workerId的值。
問題解決
1.先設置workerId為隨機數,這樣保證每個機器部署的時候拿到的都是隨機數
# 設置隨機
mybatis-plus.global-config.worker-id: ${random.int}
這里你啟動項目的時候回發(fā)現一個異常
異常很明顯,這里的worer id 必選小于31,那我們就需要修改一下隨機數
# 設置隨機
mybatis-plus.global-config.worker-id: ${random.int(1,31)}
這個時候我們先看一下我們設置參數有沒有生效,為了比較明顯看到效果,我們直接設置worker-id為一個固定值20,再斷點看一下,我們找到com.baomidou.mybatisplus.core.toolkit.IdWorker這個核心類,獲取id的核心方法是com.baomidou.mybatisplus.core.toolkit.IdWorker#getId,那我們就在這里加一個斷點看下
public class IdWorker {
/**
* 主機和進程的機器碼
*/
private static Sequence WORKER = new Sequence();
//獲取id
public static long getId() {
return WORKER.nextId();
}
public static String getIdStr() {
return String.valueOf(WORKER.nextId());
}
/**
* <p>
* 有參構造器
* </p>
*
* @param workerId 工作機器 ID
* @param datacenterId 序列號
*/
public static void initSequence(long workerId, long datacenterId) {
WORKER = new Sequence(workerId, datacenterId);
}
/**
* <p>
* 使用ThreadLocalRandom獲取UUID獲取更優(yōu)的效果 去掉"-"
* </p>
*/
public static String get32UUID() {
ThreadLocalRandom random = ThreadLocalRandom.current();
return new UUID(random.nextLong(), random.nextLong()).toString().replace(StringPool.DASH, StringPool.EMPTY);
}
}
斷點后的結果是:
這個時候看到workerId沒有生效,我們繼續(xù)分析下源碼。
項目啟動的時候,mybatis-plus 會調用一個com.baomidou.mybatisplus.core.MybatisConfiguration#init方法來初始化配置信息,我們看下代碼
public void init(GlobalConfig globalConfig) {
// 初始化 Sequence
//這里需要同時設置workerId和datacenterId
if (null != globalConfig.getWorkerId()
&& null != globalConfig.getDatacenterId()) {
IdWorker.initSequence(globalConfig.getWorkerId(), globalConfig.getDatacenterId());
}
// 打印 Banner
if (globalConfig.isBanner()) {
System.out.println(" _ _ |_ _ _|_. ___ _ | _ ");
System.out.println("| | |\\/|_)(_| | |_\\ |_)||_|_\\ ");
System.out.println(" / | ");
System.out.println(" "+MybatisPlusVersion.getVersion()+" ");
}
}
我們發(fā)現workerId和datacenterId必須同時設置才會獲取我們設置的值。
那我們就修改配置一下
# 設置隨機
mybatis-plus.global-config.worker-id: ${random.int(1,31)}
mybatis-plus.global-config.datacenter-id: ${random.int(1,31)}
這樣設置以后發(fā)現終于生效了,然后部署一下,問題終于解決了。這里問題雖然解決了,但是workerId重復其實沒有實際驗證過,如果有驗證過的同學歡迎留言。
來源:blog.csdn.net/wagnteng/
article/details/117064242
END
關注 Stephen,一起學習,一起成長。
點“在看”支持下吧
點 閱讀原文 可優(yōu)惠充值話費,流量,視頻會員等。
