MyBatis-Plus 内置雪花算法主键重复问题
点击关注上方“Stephen”,
设为“置顶或星标”,第一时间送达干货
问题描述
目前项目使用的id是mybatis-plus 内置的主键生成策略 ID_WORKER ,最近测试在做性能压测,部署架构是单服务集群的部署方式,然后就发现了id重复的异常,异常如下
问题分析
首先分析的是id生成是不是就是重复了,先关掉其中一台机器,单机跑,这个时候发现压到1000的并发都没有出现过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}
这里你启动项目的时候回发现一个异常
异常很明显,这里的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获取更优的效果 去掉"-"
* </p>
*/
public static String get32UUID() {
ThreadLocalRandom random = ThreadLocalRandom.current();
return new UUID(random.nextLong(), random.nextLong()).toString().replace(StringPool.DASH, StringPool.EMPTY);
}
}
断点后的结果是:
这个时候看到workerId没有生效,我们继续分析下源码。
项目启动的时候,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()+" ");
}
}
我们发现workerId和datacenterId必须同时设置才会获取我们设置的值。
那我们就修改配置一下
# 设置随机
mybatis-plus.global-config.worker-id: ${random.int(1,31)}
mybatis-plus.global-config.datacenter-id: ${random.int(1,31)}
这样设置以后发现终于生效了,然后部署一下,问题终于解决了。这里问题虽然解决了,但是workerId重复其实没有实际验证过,如果有验证过的同学欢迎留言。
来源:blog.csdn.net/wagnteng/ article/details/117064242
问题描述
目前项目使用的id是mybatis-plus 内置的主键生成策略 ID_WORKER ,最近测试在做性能压测,部署架构是单服务集群的部署方式,然后就发现了id重复的异常,异常如下
问题分析
首先分析的是id生成是不是就是重复了,先关掉其中一台机器,单机跑,这个时候发现压到1000的并发都没有出现过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}这里你启动项目的时候回发现一个异常
异常很明显,这里的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获取更优的效果 去掉"-"
* </p>
*/
public static String get32UUID() {
ThreadLocalRandom random = ThreadLocalRandom.current();
return new UUID(random.nextLong(), random.nextLong()).toString().replace(StringPool.DASH, StringPool.EMPTY);
}
}断点后的结果是:
这个时候看到workerId没有生效,我们继续分析下源码。
项目启动的时候,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()+" ");
}
}我们发现workerId和datacenterId必须同时设置才会获取我们设置的值。
那我们就修改配置一下
# 设置随机
mybatis-plus.global-config.worker-id: ${random.int(1,31)}
mybatis-plus.global-config.datacenter-id: ${random.int(1,31)}这样设置以后发现终于生效了,然后部署一下,问题终于解决了。这里问题虽然解决了,但是workerId重复其实没有实际验证过,如果有验证过的同学欢迎留言。
来源:blog.csdn.net/wagnteng/ article/details/117064242
END
关注 Stephen,一起学习,一起成长。
点“在看”支持下吧
点 阅读原文 可优惠充值话费,流量,视频会员等。