DefaultIdentifierGenerator 雪花演算法 生成 重複 id 解決辦法

胡歌粉絲發表於2020-11-25

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 的 stream ,既然問題定位到了,接下來要做的就是修改它。

問題解決

有兩種解決辦法。

  1. java 的 stream 預設 是 並行流,我們可以將它設定成序列流 ,例如

在這裡插入圖片描述
加上 sequential() 將其變成序列流。

  1. 寫一個 IdentifierGenerator util ,既然 DefaultIdentifierGenerator 的 Sequence 不是單例,那麼我們就在外層做操作,把呼叫到的 IdentifierGenerator 變成單例。

相關文章