LAST_INSERT_ID() 返回**當前連線**最近一次成功執行的 INSERT 或 UPDATE 語句中,第一條記錄自動生成的 AUTO_INCREMENT 值。
返回值**僅對當前連線 (Session/Connection) 可見**,完全不受其他連線插入操作影響。這是高併發環境下獲取自增 ID 的唯一正確方式。
-- 連線 A
INSERT INTO t (name) VALUES ('A');
SELECT LAST_INSERT_ID(); -- 返回 100
-- 連線 B (並發插入)
INSERT INTO t (name) VALUES ('B');
SELECT LAST_INSERT_ID(); -- 返回 101 (各自獨立,互不干擾)
對比:SELECT MAX(id) FROM t 在高併發下極不安全,極易取到其他連線的 ID。
只要在當前連線觸發了自增值生成,無論操作哪張表,LAST_INSERT_ID() 都會更新為最新的值。
INSERT INTO table_a (col) VALUES ('a'); -- id=10
INSERT INTO table_b (col) VALUES ('b'); -- id=20
SELECT LAST_INSERT_ID(); -- 返回 20 (來自 table_b)
單條 INSERT 包含多行值時,只返回第一行生成的 ID。這是為了保證主從複製 (Replication) 時,從庫重放 SQL 能獲得相同的確定性結果。
INSERT INTO t (name) VALUES ('Mary'), ('Jane'), ('Lisa');
-- 假設自增起始為 2
SELECT LAST_INSERT_ID(); -- 返回 2 (第一行 Mary 的 ID)
-- 實際插入 ID 為 2, 3, 4
若 INSERT IGNORE 因唯一鍵衝突未實際插入行,自增計數器**不增加** (InnoDB 8.0+ 行鎖優化可能預分配但不回滾),且 LAST_INSERT_ID() 返回 0。
INSERT IGNORE INTO t (uk_col) VALUES ('exists'); -- 唯一鍵衝突,忽略
SELECT LAST_INSERT_ID(); -- 返回 0
可手動設定下一次 LAST_INSERT_ID() 的返回值,常用於模擬序列或跨表關聯邏輯。
INSERT INTO parent (name) VALUES ('P1');
-- 手動將返回值設為剛插入的父 ID (假設為 100),供後續邏輯使用
SELECT LAST_INSERT_ID(100); -- 返回 100,並更新內部計數器
INSERT INTO child (parent_id) VALUES (LAST_INSERT_ID()); -- 使用 100
| 語言/框架 | 推薦獲取方式 | 避坑提示 |
|---|---|---|
| JDBC (MyBatis/JPA) | useGeneratedKeys="true" keyProperty="id" (MyBatis)@GeneratedValue (JPA) | 驅動底層調用 getGeneratedKeys(),等同 LAST_INSERT_ID(),線程安全 |
| Python (mysqlclient/PyMySQL) | cursor.lastrowid | 同連線隔離 |
| Go (database/sql) | result.LastInsertId() | 需確保同一 sql.DB 連線池複用 |
| Node.js (mysql2) | results.insertId | 連線池模式下自動綁定 |
LAST_INSERT_ID() (或驅動封裝) 獲取自增 ID,嚴禁 使用 MAX(id) 或 ORDER BY id DESC LIMIT 1。[LAST_INSERT_ID(), LAST_INSERT_ID() + affected_rows - 1] (InnoDB 連續分配時有效)。LAST_INSERT_ID(expr) 可實現複雜的跨表事務 ID 傳遞。