spring Boot集群環境下唯一ID生成策略:避免編號重復的有效方案
在分布式環境中生成全局唯一的id是一個常見挑戰。本文探討基于spring boot + mybatis-plus的id生成方案,并分析其在集群環境下可能出現id重復的原因及解決方法。該方案的核心是利用數據庫序列結合分布式鎖(redisson)保證id唯一性。
方案的核心邏輯:獲取當前日期,查詢數據庫序列表是否存在對應日期的記錄。若存在且日期相同,則遞增序列號;否則,創建新記錄。最后,更新數據庫并返回生成的ID。
然而,即使使用了redisson分布式鎖,本地單機環境測試正常,集群環境下仍然可能出現ID重復。問題根源在于事務提交時機。@Transactional(rollbackFor = Exception.class) 注解并不能保證事務在方法執行完畢后立即提交,spring框架通常在方法執行完畢或線程結束后才提交。
集群環境下,多個實例可能同時獲取鎖并執行ID生成方法。若機器時間存在微小差異,在事務提交前,不同實例可能生成相同日期,導致ID重復。分布式鎖只能保證同一時間只有一個實例訪問數據庫,無法控制事務提交時機。
為解決此問題,建議采用以下兩種方法:
方法一:使用 Propagation.REQUIRES_NEW
修改 @Transactional 注解,將 propagation 屬性設置為 Propagation.REQUIRES_NEW。這將使ID生成方法在一個新的事務中運行,并在方法結束后立即提交,避免事務提交時機不一致。修改后的注解如下:
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
方法二:使用 TransactionTemplate
更精細的控制方法是使用 TransactionTemplate 手動管理事務。TransactionTemplate 允許更精確地控制事務提交和回滾,確保ID生成方法在獨立事務中執行,并在方法結束后立即提交。
通過以上兩種方法,可以有效避免集群環境下ID重復,確保生成的ID在分布式環境下全局唯一。