不会重置。mysql 8.0重启后auto_increment值不回溯,因其将已分配的最大自增值写入redo log并持久化至数据字典,启动时重放日志并与max(id)比较取较大者加步长;show create table显示的值即为当前权威值。

事务回滚后AUTO_INCREMENT值不还原是确定性行为
执行 BEGIN; INSERT INTO t VALUES (NULL, 1, 1); ROLLBACK; 后,SHOW CREATE TABLE t 显示的 AUTO_INCREMENT 值已 +1,且无法撤销。这不是 bug,而是 InnoDB 的设计选择:自增 ID 在语句解析初期就完成预分配,早于事务判断和行写入。若允许回退,高并发下需加更重锁或做唯一性校验,性能代价远高于“跳号”。
常见错误现象:
- 开发误以为回滚能“回收”ID,结果在分页或导出逻辑中依赖连续 ID,导致漏数据或重复处理
- 用
SELECT MAX(id)做计数或断号检测,却忽略已分配未提交的 ID 段
唯一键冲突也会消耗自增ID且不可回收
建表含 UNIQUE KEY c(c),已有 (1, 1, 1),再执行 INSERT INTO t VALUES (NULL, 1, 2) 报 Duplicate entry '1' for key 'c',但 AUTO_INCREMENT 已升至 2——ID 在冲突判定前就分配了。
这个流程固定:
- 引擎先取当前自增值 → 改写 SQL 中的
NULL→ 再校验唯一约束 → 失败后丢弃整行,但 ID 不回收 - 哪怕表里只有 1 行,反复触发唯一冲突,
AUTO_INCREMENT也会一路涨上去 -
INSERT IGNORE和ON DUPLICATE KEY UPDATE同样触发预分配,只是不报错
批量插入(INSERT SELECT / LOAD DATA)默认跳号严重
默认 innodb_autoinc_lock_mode = 1 下,INSERT INTO t SELECT NULL, c, d FROM src LIMIT 5 可能一次性预申请多段 ID(如从 100 直接跳到 108),实际只用其中一部分,剩余被丢弃。
这不是配置错误,而是 InnoDB 为减少锁竞争做的并发优化:
- 设为
2(交错模式)可缓解但不消除,且要求binlog_format = ROW - 设为
0(传统全表锁)能保证连续,但吞吐暴跌,线上禁用 - 查当前模式:
SELECT @@innodb_autoinc_lock_mode - 动态改模式:
SET GLOBAL innodb_autoinc_lock_mode = 1(注意主从一致性)
MySQL 5.7 与 8.0+ 重启后行为完全不同
MySQL 5.7 及更早版本:自增值只存内存,重启后 InnoDB 扫描表数据,取 MAX(id) + 1 作为新起点。这意味着:
- 如果曾插入过
id=1000又删掉,重启后可能回到AUTO_INCREMENT = 101 -
ALTER TABLE t AUTO_INCREMENT = 500若未严格大于当前MAX(id),重启后仍被覆盖
MySQL 8.0+:自增值写入 redo log 并落盘到数据字典,重启后恢复的是最后已提交的值。验证方式:SHOW CREATE TABLE t 输出中的 AUTO_INCREMENT=xxx 就是真实持久化值。
真正容易被忽略的是:空洞本身无害,但业务若把自增 ID 当作订单号、流水号或分页依据,问题会在低概率场景(如唯一冲突突增、批量导入失败率升高)下集中爆发,排查时往往已错过时间窗口。











