MySQL中自增id用完怎么办?
MySQL中自增id用完怎么办?
MySQL里有很多自增的id,每个自增id都是定义了初始值,然后不停地往上加步长。虽然自然数是没有上限的,但是在计算机里,只要定义了表示这个数的字节长度,那它就有上限。比如,无 符号整型(unsigned int)是4个字节,上限就是2^32 - 1。
接下来我们看看MySQL里面的几种自增id,分析下它们的值达到上限之后,会出现什么情况。
一,表定义自增值id
表定义的自增值达到上限后的逻辑是:再次申请下一个id时,得到的值保持不变。
CREATE TABLE t (id INT UNSIGNED auto_increment PRIMARY KEY
) auto_increment = 4294967295;
SELECT * from t;
insert into t values(null);
SELECT * from t;
insert into t values(null);
SELECT * from t;
可以看到,第一个insert语句插入数据成功后,这个表的AUTO_INCREMENT没有改变(还是 4294967295),就导致了第二个insert语句又拿到相同的自增id值,再试图执行插入语句,报主键冲突错误。
解决方法:
2^32 - 1(4294967295)不是一个特别大的数,对于一个频繁插入删除数据的表来说,是可能会被用完的。因此在建表的时候你需要考察你的表是否有可能达到这个上限,如果有可能,就应该创 建成8个字节的bigint unsigned。
类型 字节/bytes 范围(无符号unsigned) 范围(有符号signed)
tinyint 1 0 ~ 2^8-1 -2^7 ~ 2^7-1
smallint 2 0 ~ 2^16-1 -2^15 ~ 2^15-1
mediumint 3 0 ~ 2^24-1 -2^23 ~ 2^23-1
int 4 0 ~ 2^32-1 -2^31 ~ 2^31-1
bigint 8 0 ~ 2^64-1 -2^63 ~ 2^63-1
二,InnoDB系统自增row_id
如果你创建的InnoDB表没有指定主键,那么InnoDB会给你创建一个不可见的,长度为6个字节 的row_id。InnoDB维护了一个全局的dict_sys.row_id值,所有无主键的InnoDB表,每插入一行数据,都将当前的dict_sys.row_id值作为要插入数据的row_id,然后把dict_sys.row_id的值加1。
实际上,在代码实现时row_id是一个长度为8字节的无符号长整型(bigint unsigned)。但 是,InnoDB在设计时,给row_id留的只是6个字节的长度,这样写到数据表中时只放了最后6个字节

所以row_id能写到数据表中的值,就有两个特征:
- row_id写入表中的值范围,是从0到2^48 - 1;
- 当dict_sys.row_id=2^48 时,如果再有插入数据的行为要来申请row_id,拿到以后再取最后6个字节的话就是0。
也就是说,写入表的row_id是从0开始到2^48 -1。达到上限后,下一个值就是0,然后继续循环。
验证:

从这个角度看,我们还是应该在InnoDB表中主动创建自增主键。因为,表自增id到达上限后, 再插入数据时报主键冲突错误,是更能被接受的。
毕竟覆盖数据,就意味着数据丢失,影响的是数据可靠性;报主键冲突,是插入失败,影响的是 可用性。而一般情况下,可靠性优先于可用性。
三,Xid
Xid在MySQL内部是怎么生成的呢?
redo log和binlog相配合的时候,它们有一个共同的字段叫作Xid。它在MySQL中是用来对应事务的。
MySQL内部维护了一个全局变量global_query_id,每次执行语句的时候将它赋值给Query_id, 然后给这个变量加1。如果当前语句是这个事务执行的第一条语句,那么MySQL还会同时把 Query_id赋值给这个事务的Xid。
而global_query_id是一个纯内存变量,重启之后就清零了。所以你就知道了,在同一个数据库实例中,不同事务的Xid也是有可能相同的。
但是MySQL重启之后会重新生成新的binlog文件,这就保证了,同一个binlog文件里,Xid一定是惟一的。
虽然MySQL重启不会导致同一个binlog里面出现两个相同的Xid,但是如果global_query_id达到上限后,就会继续从0开始计数。从理论上讲,还是就会出现同一个binlog里面出现相同Xid的场景。
因为global_query_id定义的长度是8个字节,这个自增值的上限是2^64 - 1。要出现这种情况,必须是下面这样的过程:
- 执行一个事务,假设Xid是A;
- 接下来执行2^64 次查询语句,让global_query_id回到A;
- 再启动一个事务,这个事务的Xid也是A。
不过,2^64 这个值太大了,大到你可以认为这个可能性只会存在于理论上。
四,Innodb trx_id
Xid和InnoDB的trx_id是两个容易混淆的概念。
Xid是由server层维护的。InnoDB内部使用Xid,就是为了能够在InnoDB事务和server之间做关联。但是,InnoDB自己的trx_id,是另外维护的。

其实,trx_id就是mvcc中用到的事务id(transaction id)。
InnoDB数据可见性的核心思想是:每一行数据都记录了更新它的trx_id,当一个事务读到一行数据的时候,判断这个数据是否可见的方法,就是通过事务的一致性视图与这行数据的trx_id做对 比。
InnoDB内部维护了一个max_trx_id全局变量,每次需要申请一个新的trx_id时,就获得 max_trx_id的当前值,然后并将max_trx_id加1。
对于正在执行的事务(活跃事务),你可以从information_schema.innodb_trx表中看到事务的一些相关信息如:trx_id。
现在,我 们一起来看一个事务现场:

事务的trx_id session B里,我从innodb_trx表里查出的这两个字段,第二个字段trx_mysql_thread_id就是线程 id。显示线程id,是为了说明这两次查询看到的事务对应的线程id都是5,也就是session A所在的线程。
可以看到,T2时刻显示的trx_id是一个很大的数;T4时刻显示的trx_id是1289,看上去是一个比 较正常的数字。这是什么原因呢?
实际上,在T1时刻,session A还没有涉及到更新,是一个只读事务。而对于只读事务,InnoDB 并不会分配trx_id。也就是说:
- 在T1时刻,trx_id的值其实就是0。而这个很大的数,只是显示用的。一会儿我会再和你说说 这个数据的生成逻辑。
- 直到session A 在T3时刻执行insert语句的时候,InnoDB才真正分配了trx_id。所以,T4时刻,session B查到的这个trx_id的值就是1289。
需要注意的是,除了显而易见的修改类语句外,如果在select 语句后面加上for update,这个事 务也不是只读事务。
实验的时候发现不止加1。这是因为:
- update 和 delete语句除了事务本身,还涉及到标记删除旧数据,也就是要把数据放到purge 队列里等待后续物理删除,这个操作也会把max_trx_id + 1, 因此在一个事务中至少加2;
- InnoDB的后台操作,比如表的索引信息统计这类操作,也是会启动内部事务的,因此你可能看到,trx_id值并不是按照加1递增的。
那么,T2时刻查到的这个很大的数字是怎么来的呢?
其实,这个数字是每次查询的时候由系统临时计算出来的。它的算法是:把当前事务的trx变量的 指针地址转成整数,再加上2^48。使用这个算法,就可以保证以下两点:
- 因为同一个只读事务在执行期间,它的指针地址是不会变的,所以不论是在 innodb_trx还是 在innodb_locks表里,同一个只读事务查出来的trx_id就会是一样的。
- 如果有并行的多个只读事务,每个事务的trx变量的指针地址肯定不同。这样,不同的并发只读事务,查出来的trx_id就是不同的。
为什么还要再加上2^48 呢?
在显示值里面加上2^48 ,目的是要保证只读事务显示的trx_id值比较大,正常情况下就会区别于读 写事务的id。但是,trx_id跟row_id的逻辑类似,定义长度也是8个字节。因此,在理论上还是可 能出现一个读写事务与一个只读事务显示的trx_id相同的情况。不过这个概率很低,并且也没有 什么实质危害,可以不管它。
只读事务不分配trx_id,有什么好处呢?
- 一个好处是,这样做可以减小事务视图里面活跃事务数组的大小。因为当前正在运行的只读 事务,是不影响数据的可见性判断的。所以,在创建事务的一致性视图时,InnoDB就只需要 拷贝读写事务的trx_id。
- 另一个好处是,可以减少trx_id的申请次数。在InnoDB里,即使你只是执行一个普通的select 语句,在执行过程中,也是要对应一个只读事务的。所以只读事务优化后,普通的查询语句 不需要申请trx_id,就大大减少了并发事务申请trx_id的锁冲突。
由于只读事务不分配trx_id,一个自然而然的结果就是trx_id的增加速度变慢了。
但是,max_trx_id会持久化存储,重启也不会重置为0,那么从理论上讲,只要一个MySQL服务 跑得足够久,就可能出现max_trx_id达到2^48 -1的上限,然后从0开始的情况。
当达到这个状态后,MySQL就会持续出现一个脏读的bug,我们来复现一下这个bug。
首先我们需要把当前的max_trx_id先修改成2^48 -1。注意:这个case里使用的是可重复读隔离级 别。具体的操作流程如下:
create table t(id int primary key, c int)engine=innodb;
insert into t values(1,1);
gdb -p <pid.mysqld> -ex 'p trx_sys->max_trx_id=281474976710655' --batch;

由于我们已经把系统的max_trx_id设置成了2^48 -1,所以在session A启动的事务TA的低水位就是 2^48 - 1。
在T2时刻,session B执行第一条update语句的事务id就是2^48 - 1,而第二条update语句的事务id 就是0了,这条update语句执行后生成的数据版本上的trx_id就是0。
在T3时刻,session A执行select语句的时候,判断可见性发现,c=3这个数据版本的trx_id,小于事务TA的低水位,因此认为这个数据可见。
但,这个是脏读。
由于低水位值会持续增加,而事务id从0开始计数,就导致了系统在这个时刻之后,所有的查询都会出现脏读的。
并且,MySQL重启时max_trx_id也不会清0,也就是说重启MySQL,这个bug仍然存在。
那么,这个bug也是只存在于理论上吗?
假设一个MySQL实例的TPS是每秒50万,持续这个压力的话,在17.8年后,就会出现这个情 况。如果TPS更高,这个年限自然也就更短了。但是,从MySQL的真正开始流行到现在,恐怕 都还没有实例跑到过这个上限。不过,这个bug是只要MySQL实例服务时间够长,就会必然出现的。
五,thread_id
接下来,我们再看看线程id(thread_id)。其实,线程id才是MySQL中最常见的一种自增id。平时我们在查各种线程的时候,show processlist里面的第一列,就是thread_id。
thread_id的逻辑很好理解:系统保存了一个全局变量thread_id_counter,每新建一个连接,就 将thread_id_counter赋值给这个新连接的线程变量。
thread_id_counter定义的大小是4个字节,因此达到2^32 -1后,它就会重置为0,然后继续增加。 但是,你不会在show processlist里看到两个相同的thread_id。
这,是因为MySQL设计了一个唯一数组的逻辑,给新线程分配thread_id的时候,逻辑代码是这 样的:
do {
new_id= thread_id_counter++;
} while (!thread_ids.insert_unique(new_id).second);
总结
每种自增id有各自的应用场景,在达到上限后的表现也不同:
- 表的自增id达到上限后,再申请时它的值就不会改变,进而导致继续插入数据时报主键冲突 的错误。
- row_id达到上限后,则会归0再重新递增,如果出现相同的row_id,后写的数据会覆盖之前 的数据。
- Xid只需要不在同一个binlog文件中出现重复值即可。虽然理论上会出现重复值,但是概率极 小,可以忽略不计。
- InnoDB的max_trx_id 递增值每次MySQL重启都会被保存起来,所以我们文章中提到的脏读 的例子就是一个必现的bug,好在留给我们的时间还很充裕。
- thread_id是我们使用中最常见的,而且也是处理得最好的一个自增id逻辑了。
不同的自增id有不同的上限值,上限值的大小取决于声明的类型长度。
相关文章:
MySQL中自增id用完怎么办?
MySQL中自增id用完怎么办? MySQL里有很多自增的id,每个自增id都是定义了初始值,然后不停地往上加步长。虽然自然数是没有上限的,但是在计算机里,只要定义了表示这个数的字节长度,那它就有上限。比如&#…...
C语言常见算法
算法(Algorithm):计算机解题的基本思想方法和步骤。算法的描述:是对要解决一个问题或要完成一项任务所采取的方法和步骤的描述,包括需要什么数据(输入什么数据、输出什么结果)、采用什么结构、使…...
0-1背包的初始化问题
题目链接 这道题的状态转移方程比较易于确定。dp[i][j]表示能放前i个物品的情况下,容量为j时能放物品的数量(这道题歌曲数量对应物品数量,容量对应时间)。 技巧(收获) 二维dp数组可以视情况优化为一维dp数组…...
API之 要求接口上传pdf 以 合同PDF的二进制数据,multpart方式上传
实现 //时间戳13位毫秒private function getMillisecond() {list($s1,$s2) explode( ,microtime());return (float)sprintf(%.0f,(floatval($s1) floatval($s2)) * 1000);}// 组装参数private function gysscPost1($url,$data){// $data[timestamp] 1694402111964;$data[tim…...
C语言-求阶乘序列前N项和
本题要求编写程序,计算序列 1!2!3!⋯ 的前N项之和。 输入格式: 输入在一行中给出一个不超过12的正整数N。 输出格式: 在一行中输出整数结果。 输入样例: 5输出样例: 153 #include "stdio.h" int main(){int n;int sum 0;scanf("%d",&a…...
3:kotlin 逻辑控制(Control flow)
像其他语言一样,kotlin也有循环和逻辑控制 条件判断(Conditional expressions) kotlin使用if和when来进行条件判断 如果纠结选择if还是when,建议使用when,因为它更能提高程序的健壮性 if 普通写法 fun main() {val…...
Linux系统之一次性计划任务at命令的基本使用
Linux系统之一次性计划任务at命令的基本使用 一、at命令介绍二、at命令的使用帮助2.1 at命令的help帮助信息2.2 at命令的语法解释 三、at命令的日常使用3.1 立即执行一次性任务3.2 指定时间执行一次性任务3.3 查询计划任务3.4 其他指定时间用法3.5 删除已经设置的计划任务3.6 显…...
记录:Unity脚本的编写8.0
目录 需求分析设计GUI包含账号和密码输入栏,包括登录和注册按键添加背景音乐编写脚本控制音乐 退出按钮编写脚本 背景图片完整代码 一个小demo,登录和注册的实现(包括GUI和数据库操控) 需求分析 自行设计GUI,要求 1.包…...
OpenCV | 模版匹配
import cv2 #opencv读取的格式是BGR import numpy as np import matplotlib.pyplot as plt#Matplotlib是RGB %matplotlib inline 模版匹配 模版匹配和卷积原理很像,模版在原图像上从原点开始滑动,计算模版与(图像被模版覆盖的地方ÿ…...
【算法刷题】Day7
文章目录 283. 移动零1089. 复写零 283. 移动零 原题链接 看到题目,首先看一下题干的要求,是在原数组内进行操作,平切保持非零元素的相对顺序 这个时候我们看到了示例一: [ 0, 1, 0, 3,12 ] 这个时候输出成为了 [ 1, 3, 12, 0, …...
前端 | iframe框架标签应用
文章目录 📚嵌入方式📚图表加载显示📚100%嵌入及滑动条问题📚加载动画保留 前情提要: 计划用iframe把画好的home1.html(echarts各种图表组成的html数据大屏)嵌入整合到index.html(搭…...
linux -系统通用命令查询
有时候内网环境下,系统有些命令没有安装因此掌握一些通用的linux 命令也可以帮助我们解决一些问题查看 1.查看系统内核版本 uname -r2.查看系统版本 cat /etc/os-release3. 查看cpu 配置 lscpu4.查看内存信息 free [参数] 中各个数值的解释如下表 数值解释t…...
python炒股自动化(1),量化交易接口区别
要实现股票量化程序化自动化,就需要券商提供的API接口,重点是个人账户小散户可以申请开通,上手要简单,接口要足够全面,功能完善,首先,第一步就是要找对渠道和方法,这里我们不讨论量化…...
LeetCode(35)螺旋矩阵【矩阵】【中等】
目录 1.题目2.答案3.提交结果截图 链接: 54. 螺旋矩阵 1.题目 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。 示例 1: 输入:matrix [[1,2,3],[4,5,6],[7,8,9]] 输出:…...
BeanUtil.copyProperties的优化与使用(解决copyProperties null值覆盖问题)
BeanUtil.copyProperties的优化与使用 前言一、copyProperties是什么?二、使用步骤1.引入库2.基础使用3.进阶使用4.实用场景 总结 前言 BeanUtil.copyProperties的优化与使用 一、copyProperties是什么? 在java中,我们想要将一个类的值赋值…...
Redis基本操作及使用
📑前言 本文主要是【Redis】——Redis基本操作及使用的文章,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是听风与他🥇 ☁️博客首页:CSDN主页听风与他 🌄每日一…...
python 继承父类的变量和方法
[root@zz python]# cat a1.py # !/usr/bin/env python # -*- coding: utf-8 -*- class AddrBookEntry(object): ##类定义 def __init__(self,a,b): ##定义构造器 self.var1=a+9 self.var2=b+11 def updatePhone(self, num): # 定义方法 sel…...
ubuntu22.04新机使用(换源,下载软件,安装显卡驱动,锁屏长亮)
换源 国内有很多Ubuntu的镜像源,包括阿里的、网易的,还有很多教育网的源,比如:清华源、中科大源。推荐使用中科大源,快得很。 /etc/apt/sources.list编辑/etc/apt/sources.list文件, 在文件最前面添加以下条目(操作前…...
如何给shopify的网址做301跳转
很多shopify的运营者或者推广者由于缺货或者货物变更,又或者自己更换了使用的主题,导致自己的URL结构发生了变化,由于不想浪费掉自己原有URL 的流量,就想做个301跳转,让自己新的网址来承接原有的流量。接下来给大家介绍…...
Redis之秒杀系统
目录 Redis 秒杀 Mysql数据库设计 Mysql秒杀实现 MysqlRedis秒杀实现 秒杀是一种高并发场景,通常指的是在短时间内(秒级别)有大量用户同时访问某个商品或服务,争相抢购的情景。在这种情况下,系统需要处理大量并发请…...
未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...
【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...
淘宝扭蛋机小程序系统开发:打造互动性强的购物平台
淘宝扭蛋机小程序系统的开发,旨在打造一个互动性强的购物平台,让用户在购物的同时,能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机,实现旋转、抽拉等动作,增…...
