MySQL:LAST_INSERT_ID()
- 基於連線,不受其他客戶端影響,無需鎖定。
- 單一
INSERT 多列時,僅回傳第一列產生的 ID。
- 範例:
INSERT INTO t VALUES (NULL,'a'),(NULL,'b'),(NULL,'c');
SELECT LAST_INSERT_ID(); -- 回傳第一列的 ID
SQL Server:三大函數比較
| 函數 | 範圍 | 觸發器影響 | 典型用途 |
@@IDENTITY | 目前連線、所有作用域、所有資料表 | 受觸發器插入影響(回傳觸發器中最後插入的 ID) | 簡單環境、無觸發器 |
SCOPE_IDENTITY() | 目前連線、目前作用域、所有資料表 | 不受觸發器影響(回傳本作用域最後插入的 ID) | 推薦、最安全 |
IDENT_CURRENT('table') | 指定資料表、所有連線、所有作用域 | 不受作用域限制,回傳該表最後產生的 ID | 跨連線監控、複寫稽核 |
觸發器情境示範
CREATE TABLE T1 (id INT IDENTITY, val VARCHAR(10));
CREATE TABLE T2 (id INT IDENTITY, val VARCHAR(10));
GO
CREATE TRIGGER trg_T1 ON T1 AFTER INSERT AS
INSERT INTO T2 (val) SELECT 'from trigger';
GO
INSERT INTO T1 (val) VALUES ('direct');
SELECT @@IDENTITY; -- 回傳 T2 的 ID(觸發器插入)
SELECT SCOPE_IDENTITY(); -- 回傳 T1 的 ID(本作用域)
SELECT IDENT_CURRENT('T1'), IDENT_CURRENT('T2');
並發壓測結論(摘錄)
@@IDENTITY 在高並發下極易衝突(萬行級即失效)。
SCOPE_IDENTITY() 經測試零衝突,可放心用於預存程序、觸發器巢狀。
IDENT_CURRENT 適合單表監控,不適用多表作用域。
最佳實務建議
- 預設使用
SCOPE_IDENTITY()。
- 若在觸發器中需取得觸發器內插入的 ID,改用
@@IDENTITY。
- 跨連線稽核才用
IDENT_CURRENT。
- Oracle 使用
RETURNING INTO、PostgreSQL 使用 RETURNING、SQLite 使用 last_insert_rowid()。