LAST_INSERT_ID() 是獲取上一條 AUTO_INCREMENT 值的標準函數,但其「連接級隔離」與「批次插入只返回首值」兩大特性常被誤解。本文從原理、行為、復制安全三個維度深度解析。
LAST_INSERT_ID 值,互不干擾。無需加鎖、無需事務,天然線程安全。INSERT INTO t VALUES (NULL),(NULL),(NULL); 只返回第一行生成的 ID,後續 ID 需自行推算(首值 + 1, +2…)。INSERT、UPDATE ... AUTO_INCREMENT、LOAD DATA 影響;SELECT、DELETE、COMMIT/ROLLBACK 不改變其值。CREATE TABLE t (id INT AUTO_INCREMENT PRIMARY KEY, v INT);
-- 單行插入
INSERT INTO t (v) VALUES (1);
SELECT LAST_INSERT_ID(); -- 返回 1
-- 批次插入 3 行
INSERT INTO t (v) VALUES (2),(3),(4);
SELECT LAST_INSERT_ID(); -- 返回 2(首行 ID),而非 4
-- 另一連接並發插入
-- Connection B:
INSERT INTO t (v) VALUES (99);
SELECT LAST_INSERT_ID(); -- 返回 5,完全不受 Connection A 影響
**為了 Statement-based Replication(SBR)安全**。
INSERT,Binlog 記錄完整語句。LAST_INSERT_ID() 返回末值,從庫再次調用會得到不同結果,導致主從不一致。SELECT LAST_INSERT_ID() 絕對可靠。INSERT ... RETURNING id(MariaDB 10.5+ / MySQL 8.0.27+ 支援)。LAST_INSERT_ID(expr):將下一次 LAST_INSERT_ID() 返回值設為 expr,常用於應用層自行分配 ID 後同步給資料庫。mysql_insert_id() (C API) / mysqli_insert_id() (PHP) / connection.insert_id() (Python) — 驅動層封裝,同樣連接級隔離。理解這三點,能避開 90% 關於自增 ID 獲取的坑。