MySQL AUTO_INCREMENT 不連續根因:唯一鍵衝突、事務回滾、批量插入預分配
自增 ID 不連續是正常行為,非 Bug。本文通過實測複現三大典型場景:唯一鍵衝突報錯、事務回滾、批量插入預分配,解析 InnoDB 自增鎖與序列分配機制。
實測複現過程
CREATE TABLE person_list (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(15) NOT NULL,
sex VARCHAR(15) DEFAULT '中',
ID_C VARCHAR(20) NOT NULL UNIQUE, -- 唯一鍵
vocation VARCHAR(8),
salary FLOAT DEFAULT 0.0
) CHARSET=utf8;
-- 正常插入 1~7
INSERT ...; -- id 1~7 連續
-- 插入 id=8 因 ID_C 衝突報錯 (Duplicate entry)
-- 再次插入 id=9 成功 → id 跳至 10
-- 故意連續 10 次衝突插入
-- 再插入成功 → id 跳至 25 (10+15)
三大根因深度解析
| 場景 | 機制 | ID 影響 |
| 唯一鍵/主鍵衝突報錯 | InnoDB 預分配自增值 → 執行插入 → 唯一檢查失敗 → 回滾 → **自增值不回收** | 每次衝突 +1 |
| 事務回滾 | 事務內獲取自增值 → 回滾 → **自增值不回收** | 每次回滾 +1 |
| 批量插入 (INSERT ... VALUES(),()...) | 預分配連續區間(預設 8-32 個)→ 實際用完釋放剩餘 → **下次從區間末尾+1 開始** | 批次大小相關 |
InnoDB 自增鎖模式 (innodb_autoinc_lock_mode)
| 模式 | 值 | 特性 | 適用 |
| Traditional | 0 | 表級自增鎖,語句結束釋放,嚴格連續 | 主從基於 Statement 复制 |
| Consecutive | 1 | 簡單 INSERT 表鎖,批量 INSERT 輕量鎖,預分配 | **預設**,效能平衡 |
| Interleaved | 2 | 無自增鎖,輕量互斥量,最大並發,ID 可能交錯 | 高併發、Row 复制 |
生產預設模式 1,**不保證連續、不保證單調遞增(極罕見並發交錯)**,僅保證**唯一、遞增趨勢**。
常見誤區與對策
- ❌ 以為自增 ID 必須連續 → **業務邏輯不可依賴連續性**。
- ❌ 用
MAX(id)+1 手動分配 → 並發極易衝突、效能差。
- ✅ 業務需連續編號(如發票號)→ 獨立序列表 + 行鎖
SELECT ... FOR UPDATE 串行分配。
- ✅ 定期整理碎片 ID → 僅靜態歸檔表可考慮
ALTER TABLE AUTO_INCREMENT=N,線上表**嚴禁**。
- ✅ 監控自增上限:
SHOW TABLE STATUS LIKE 't'\G 觀察 Auto_increment,防 BIGINT 耗盡。
驗證查詢
-- 查看下一個自增值
SHOW TABLE STATUS LIKE 'person_list'\G
-- Auto_increment: 25
-- 查看表結構
SHOW CREATE TABLE person_list\G
- 上一篇文章: MySQL 忘記 Root 密碼重置全攻略:Skip-Grant-Tables、Init-File、Windows/Linux 通用
- 下一篇文章: MySQL 5.5 升級 5.6 TIMESTAMP 行為變更兼容指南
Copyright ©
程式碼之家 All Rights Reserved