mybatis-plus 雪花算法id冲突问题解决、雪花算法id冲突、雪花算法、id冲突解决、id、id冲突、主键冲突

2024-09-05 10:36

本文主要是介绍mybatis-plus 雪花算法id冲突问题解决、雪花算法id冲突、雪花算法、id冲突解决、id、id冲突、主键冲突,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

mybatis-plus 雪花算法id冲突问题解决、雪花算法id冲突、雪花算法、id冲突解决、id、id冲突、主键冲突

问题:
k8s里起了多个pod,发现mybatis-plus的雪花算法不同pod之前生成了相同的id

问题原因:
mybatis-plus默认id生成器生成datacenterId时是读取的机器网卡mac地址后两个字节,生成一个0~31的数字,这里有很大机率生成相同的datacenterId值
mybatis-plus默认id生成器生成workerId时是读取的jvm pid,但是k8s里pod的jvm pid不作处理时默认都是1,导致datacenterId + workerId有很大机率不同的pod拥有相同的值

分析日志:
ee:dc:39:3f:1a:53
531a >> 6 = 0101001100
0101001100 % 32 = 01100

86:65:49:0a:d1:f4
f4d1 >> 6 = 1111010011
1111010011 % 32 = 10011

e2:71:3a:cc:31:c3
c331 >> 6 = 1100001100
1100001100 % 32 = 01100

解决思路:
不同的pod之间分配唯一的datacenterId、workerId,使生成的雪花算法id不会产生冲突

解决方案(已实际使用并已通过测试):

//程序配置
application.yml:mybatis-plus-ext:snowflake:redis-key: smarthome.mybatis-plus-ext.snowflake.redis-key #mybatis-plus 雪花算法生成器配置。解决多个pod情况下生成的 数据中心id+workerId 重复的问题的redis键值


 

//配置类
MybatisPlusSnowflakeConfig.java:package com.onbright.smarthome.config;import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;/*** <p>* mybatis-plus 雪花算法生成器配置。解决多个pod情况下生成的 数据中心id+workerId 重复的问题* </p>*/
@Slf4j
@Configuration
public class MybatisPlusSnowflakeConfig {@Autowiredprivate RedisTemplate redisTemplate;@Value("${mybatis-plus-ext.snowflake.redis-key}")private String redisKey;@Beanpublic IdentifierGenerator identifierGenerator(){//testedLong redisIncrementValue = redisTemplate.opsForValue().increment(redisKey, 1L);if (redisIncrementValue == null || redisIncrementValue < 0L){throw new RuntimeException(String.format("程序启动失败, 使用redis获取到的雪花算法索引值异常, %s", redisIncrementValue));}//tested//从redis索引值中取出dataCenterId、workerIdMutablePair<Long, Long> longLongMutablePair = generateDatacenterIdAndWorkerIdFromIndex(redisIncrementValue);Long dataCenterId = longLongMutablePair.getLeft();Long workerId = longLongMutablePair.getRight();//tested//再次检查dataCenterId、workerId值if (dataCenterId == null || dataCenterId < 0L || dataCenterId > 31L|| workerId == null || workerId < 0L || workerId > 31L){throw new RuntimeException(String.format("程序启动失败, 使用雪花算法索引值算出的dataCenterId,workerId异常, %s, %s, %s", redisIncrementValue, dataCenterId, workerId));}log.info("mybatis-plus雪花算法datacenterId,workerId生成, redisIncrementValue: {}, dataCenterId: {}, workerId: {}", redisIncrementValue, dataCenterId, workerId);return new DefaultIdentifierGenerator(workerId, dataCenterId);}/*** 从index值中生成雪花算法的datacenterId(5bit)、workerId(5bit)** @param index 索引值,如:1。必须为大于等于0的值* @return 返回生成好的用MutablePair包装的datacenterId(left)、workerId(right),其中datacenterId值范围为0~31,workerId值范围也为0~31,如:{0,0}、{1、1}、{0,1}、{0,31}、{31,31}* @throws IllegalArgumentException 当参数索引值小于0时会抛出异常*/public static MutablePair<Long, Long> generateDatacenterIdAndWorkerIdFromIndex(long index) {if (index < 0) {throw new IllegalArgumentException("索引值不能为负数");}long indexBucket = index % 1024L;long dataCenterId = indexBucket / 32L;long workerId = indexBucket % 32L;return MutablePair.of(dataCenterId, workerId);}}//测试核心函数
MybatisPlusSnowflakeConfigTest.java:package com.onbright.smarthome.config;import org.apache.commons.lang3.tuple.MutablePair;
import org.junit.Assert;
import org.junit.Test;public class MybatisPlusSnowflakeConfigTest {@Testpublic void generateDatacenterIdAndWorkerIdFromIndex() {//legal{MutablePair<Long, Long> longLongMutablePair = MybatisPlusSnowflakeConfig.generateDatacenterIdAndWorkerIdFromIndex(0L);Assert.assertEquals(0L, longLongMutablePair.getLeft().longValue());Assert.assertEquals(0L, longLongMutablePair.getRight().longValue());}{MutablePair<Long, Long> longLongMutablePair = MybatisPlusSnowflakeConfig.generateDatacenterIdAndWorkerIdFromIndex(1L);Assert.assertEquals(0L, longLongMutablePair.getLeft().longValue());Assert.assertEquals(1L, longLongMutablePair.getRight().longValue());}{MutablePair<Long, Long> longLongMutablePair = MybatisPlusSnowflakeConfig.generateDatacenterIdAndWorkerIdFromIndex(2L);Assert.assertEquals(0L, longLongMutablePair.getLeft().longValue());Assert.assertEquals(2L, longLongMutablePair.getRight().longValue());}{MutablePair<Long, Long> longLongMutablePair = MybatisPlusSnowflakeConfig.generateDatacenterIdAndWorkerIdFromIndex(31L);Assert.assertEquals(0L, longLongMutablePair.getLeft().longValue());Assert.assertEquals(31L, longLongMutablePair.getRight().longValue());}{MutablePair<Long, Long> longLongMutablePair = MybatisPlusSnowflakeConfig.generateDatacenterIdAndWorkerIdFromIndex(32L);Assert.assertEquals(1L, longLongMutablePair.getLeft().longValue());Assert.assertEquals(0L, longLongMutablePair.getRight().longValue());}{MutablePair<Long, Long> longLongMutablePair = MybatisPlusSnowflakeConfig.generateDatacenterIdAndWorkerIdFromIndex(33L);Assert.assertEquals(1L, longLongMutablePair.getLeft().longValue());Assert.assertEquals(1L, longLongMutablePair.getRight().longValue());}{MutablePair<Long, Long> longLongMutablePair = MybatisPlusSnowflakeConfig.generateDatacenterIdAndWorkerIdFromIndex(63L);Assert.assertEquals(1L, longLongMutablePair.getLeft().longValue());Assert.assertEquals(31L, longLongMutablePair.getRight().longValue());}{MutablePair<Long, Long> longLongMutablePair = MybatisPlusSnowflakeConfig.generateDatacenterIdAndWorkerIdFromIndex(64L);Assert.assertEquals(2L, longLongMutablePair.getLeft().longValue());Assert.assertEquals(0L, longLongMutablePair.getRight().longValue());}{MutablePair<Long, Long> longLongMutablePair = MybatisPlusSnowflakeConfig.generateDatacenterIdAndWorkerIdFromIndex(991L);Assert.assertEquals(30L, longLongMutablePair.getLeft().longValue());Assert.assertEquals(31L, longLongMutablePair.getRight().longValue());}{MutablePair<Long, Long> longLongMutablePair = MybatisPlusSnowflakeConfig.generateDatacenterIdAndWorkerIdFromIndex(992L);Assert.assertEquals(31L, longLongMutablePair.getLeft().longValue());Assert.assertEquals(0L, longLongMutablePair.getRight().longValue());}{MutablePair<Long, Long> longLongMutablePair = MybatisPlusSnowflakeConfig.generateDatacenterIdAndWorkerIdFromIndex(993L);Assert.assertEquals(31L, longLongMutablePair.getLeft().longValue());Assert.assertEquals(1L, longLongMutablePair.getRight().longValue());}{MutablePair<Long, Long> longLongMutablePair = MybatisPlusSnowflakeConfig.generateDatacenterIdAndWorkerIdFromIndex(1023L);Assert.assertEquals(31L, longLongMutablePair.getLeft().longValue());Assert.assertEquals(31L, longLongMutablePair.getRight().longValue());}{MutablePair<Long, Long> longLongMutablePair = MybatisPlusSnowflakeConfig.generateDatacenterIdAndWorkerIdFromIndex(1024L);Assert.assertEquals(0L, longLongMutablePair.getLeft().longValue());Assert.assertEquals(0L, longLongMutablePair.getRight().longValue());}//integer.max{MutablePair<Long, Long> longLongMutablePair = MybatisPlusSnowflakeConfig.generateDatacenterIdAndWorkerIdFromIndex(2147483647L);Assert.assertEquals(31L, longLongMutablePair.getLeft().longValue());Assert.assertEquals(31L, longLongMutablePair.getRight().longValue());}//long.max{MutablePair<Long, Long> longLongMutablePair = MybatisPlusSnowflakeConfig.generateDatacenterIdAndWorkerIdFromIndex(9223372036854775807L);Assert.assertEquals(31L, longLongMutablePair.getLeft().longValue());Assert.assertEquals(31L, longLongMutablePair.getRight().longValue());}//illegal{Assert.assertEquals("索引值不能为负数", Assert.assertThrows(IllegalArgumentException.class, () -> MybatisPlusSnowflakeConfig.generateDatacenterIdAndWorkerIdFromIndex(-1)).getMessage());}}
}

这篇关于mybatis-plus 雪花算法id冲突问题解决、雪花算法id冲突、雪花算法、id冲突解决、id、id冲突、主键冲突的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1138715

相关文章

深度剖析SpringBoot日志性能提升的原因与解决

《深度剖析SpringBoot日志性能提升的原因与解决》日志记录本该是辅助工具,却为何成了性能瓶颈,SpringBoot如何用代码彻底破解日志导致的高延迟问题,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言第一章:日志性能陷阱的底层原理1.1 日志级别的“双刃剑”效应1.2 同步日志的“吞吐量杀手”

MySQL 表空却 ibd 文件过大的问题及解决方法

《MySQL表空却ibd文件过大的问题及解决方法》本文给大家介绍MySQL表空却ibd文件过大的问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录一、问题背景:表空却 “吃满” 磁盘的怪事二、问题复现:一步步编程还原异常场景1. 准备测试源表与数据

解决Nginx启动报错Job for nginx.service failed because the control process exited with error code问题

《解决Nginx启动报错Jobfornginx.servicefailedbecausethecontrolprocessexitedwitherrorcode问题》Nginx启... 目录一、报错如下二、解决原因三、解决方式总结一、报错如下Job for nginx.service failed bec

SysMain服务可以关吗? 解决SysMain服务导致的高CPU使用率问题

《SysMain服务可以关吗?解决SysMain服务导致的高CPU使用率问题》SysMain服务是超级预读取,该服务会记录您打开应用程序的模式,并预先将它们加载到内存中以节省时间,但它可能占用大量... 在使用电脑的过程中,CPU使用率居高不下是许多用户都遇到过的问题,其中名为SysMain的服务往往是罪魁

MySQ中出现幻读问题的解决过程

《MySQ中出现幻读问题的解决过程》文章解析MySQLInnoDB通过MVCC与间隙锁机制在可重复读隔离级别下解决幻读,确保事务一致性,同时指出性能影响及乐观锁等替代方案,帮助开发者优化数据库应用... 目录一、幻读的准确定义与核心特征幻读 vs 不可重复读二、mysql隔离级别深度解析各隔离级别的实现差异

C++ vector越界问题的完整解决方案

《C++vector越界问题的完整解决方案》在C++开发中,std::vector作为最常用的动态数组容器,其便捷性与性能优势使其成为处理可变长度数据的首选,然而,数组越界访问始终是威胁程序稳定性的... 目录引言一、vector越界的底层原理与危害1.1 越界访问的本质原因1.2 越界访问的实际危害二、基

Python多线程应用中的卡死问题优化方案指南

《Python多线程应用中的卡死问题优化方案指南》在利用Python语言开发某查询软件时,遇到了点击搜索按钮后软件卡死的问题,本文将简单分析一下出现的原因以及对应的优化方案,希望对大家有所帮助... 目录问题描述优化方案1. 网络请求优化2. 多线程架构优化3. 全局异常处理4. 配置管理优化优化效果1.

MyBatis-Plus 与 Spring Boot 集成原理实战示例

《MyBatis-Plus与SpringBoot集成原理实战示例》MyBatis-Plus通过自动配置与核心组件集成SpringBoot实现零配置,提供分页、逻辑删除等插件化功能,增强MyBa... 目录 一、MyBATis-Plus 简介 二、集成方式(Spring Boot)1. 引入依赖 三、核心机制

Java报错:org.springframework.beans.factory.BeanCreationException的五种解决方法

《Java报错:org.springframework.beans.factory.BeanCreationException的五种解决方法》本文解析Spring框架中BeanCreationExce... 目录引言一、问题描述1.1 报错示例假设我们有一个简单的Java类,代表一个用户信息的实体类:然后,

MyBatis的xml中字符串类型判空与非字符串类型判空处理方式(最新整理)

《MyBatis的xml中字符串类型判空与非字符串类型判空处理方式(最新整理)》本文给大家介绍MyBatis的xml中字符串类型判空与非字符串类型判空处理方式,本文给大家介绍的非常详细,对大家的学习或... 目录完整 Hutool 写法版本对比优化为什么status变成Long?为什么 price 没事?怎