DefaultIdentifierGenerator 雪花算法 生成 重複 id
-
- 前言
- 問題發生
- 排查原因
- 問題解決
前言
利用 mybatisplus 的 DefaultIdentifierGenerator 生成 id 當做主鍵,人家的代碼沒有問題,是自己程式代碼問題導緻。
問題發生
利用 mybatisplus 的 DefaultIdentifierGenerator 生成 id 當做主鍵,然後批量新增資料後,丫的報錯了
BatchUpdateException: Duplicate entry '1331426208168046594' for key 'PRIMARY'"
主鍵沖突!!!!
可是建立的 id 是用方法生成了啊 (ノへ ̄、)
private Number createId() {
IdentifierGenerator identifierGenerator = new DefaultIdentifierGenerator();
return identifierGenerator.nextId(new Object());
}
排查原因
接下來就是排查原因了,首先看一下它源碼是怎麼生成資料的。

首先看到了鎖,java 在jdk1.6之後優化了 synchronized ,使得它不會是直接變成重量級鎖,是以調用此方法并不會有并發問題,且對同一毫秒的判斷序列号也自增了,理論上并不會出現重複id的情況。
觀察一遍發現問題所在。
它的 時間判斷參數是一個成員變量,生命周期跟着 目前類走。
而調用的方法并不是個單例模式,是以每次建立一個對象,其内部判定的時間判斷參數都是獨立存在的,這樣的話在并行程式的過程中,是有可能生成相同的id的。
原本懷疑是否是使用了 java 8 的 stream 的原因。然而發現,人家預設就是串行流,要使用并行流是需要而外加方法的,是以和這個沒有關系。
問題解決
有兩種方式解決:
- 寫一個 IdentifierGenerator util ,既然 DefaultIdentifierGenerator 的 Sequence 不是單例,那麼我們就在外層做操作,把調用到的 IdentifierGenerator 變成單例。
- IdWorker 這個類是 MyBatis Plus 雪花算法的實作,直接調用其方法擷取,它内部是單例實作的。ps(若沒有特殊需求,用官方提供的就好了)