场景描述:原设置主键类型为bigint,发现自增时存在跨值问题(非顺序递增),查询相关配置无明显问题,更新主键类型为int,重建表后,写入时,主键仍为Long类型。db执行写入命令无异常,应该是代码问题。
show session variables like ‘%auto_inc%’;
show global variables like ‘%auto_inc%’;
show table status like ‘db_name’;
问题定位:查看源码,发现主键ID根据配置指定由com.baomidou.mybatisplus.core.toolkit.Sequence(雪花算法)生成,生成方法如下:
public synchronized long nextId() {
long timestamp = timeGen();
//闰秒
if (timestamp < lastTimestamp) {
long offset = lastTimestamp - timestamp;
if (offset <= 5) {
try {
wait(offset << 1);
timestamp = timeGen();
if (timestamp < lastTimestamp) {
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", offset));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", offset));
}
}
if (lastTimestamp == timestamp) {
// 相同毫秒内,序列号自增
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
// 同一毫秒的序列数已经达到最大
timestamp = tilNextMillis(lastTimestamp);
}
} else {
// 不同毫秒内,序列号置为 1 - 3 随机数
sequence = ThreadLocalRandom.current().nextLong(1, 3);
}
lastTimestamp = timestamp;
// 时间戳部分 | 数据中心部分 | 机器标识部分 | 序列号部分
return ((timestamp - twepoch) << timestampLeftShift)
| (datacenterId << datacenterIdShift)
| (workerId << workerIdShift)
| sequence;
}
结果:主键注解未设置自增类型,所以使用了默认的分布式主键生成方式。
拓展:雪花算法生成ID主键重复问题(参考文档:https://zhuanlan.zhihu.com/p/707877829)