mysql LAST_INSERT_ID 使用與注意事項
阿新 • • 發佈:2019-02-11
在使用MySQL時,若表中含自增欄位(auto_increment型別),則向表中insert一條記錄後,可以呼叫last_insert_id()來獲得最近insert的那行記錄的自增欄位值
$mdb->lastInsertId();
但事實上,使用last_insert_id()時有很多注意事項,否則很容易踩到坑。
若在同一條insert語句中插入多行(如"insert into tbl_name (col_a, col_b) values ('aa', 'bb'), ('aaa', 'bbb')"這類SQL語句),則last_insert_id()返回的自增欄位的"當前值"只在舊值的基礎上加1,這與實際情況不符(表中的實際情況是自增欄位值在舊值基礎上加N)!
3. 假設用形如"INSERT ... ON DUPLICATE KEY UPDATE"的SQL語句更新表,此時,若該語句的實際作用是insert操作時,呼叫last_insert_id()會返回本次insert後自增欄位的當前值;而若該語句的實際作用是update操作時,呼叫last_insert_id()返回的是自增欄位的 舊值,而非當前更新行的自增欄位值,所以這個值無意義(因為呼叫last_insert_id()是想獲取sql影響到的行的自增欄位值進而做其它邏輯業務的,如果得到的值並非sql操作影響到的行對應的自增值,則這個值對業務來說無意義),按照MySQL手冊的說明,若業務開發者想得到實際update操作影響到的行的自增值,可以用形如"INSERT
INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), c=3;"的SQL語句來獲取。
關於帶引數的last_insert_id()函式的使用說明,可以參考本文 第8條的說明。
若在SQL中顯式指定自增欄位的值,如假設某張表由兩列(id,
name)構成,其中id為自增型別,假設當前表中id值為2,那麼,執行"insert into test_tbl (id, name) values (11, 'test3');"後,再執行"select last_insert_id()",可以發現,得到的結果依舊是2。也即,只有自增欄位由mysql來分配時,last_insert_id()才可能得到正確的值;SQL中顯式更新自增欄位值時,last_insert_id()返回的值不可用!
如果sql語句執行出錯,則呼叫last_insert_id()的值未定義 。例如,若事務因執行出錯回滾,則last_insert_id()的值不會恢復到事務執行前的那個值。
last_insert_id()的值是由MySQL server來維護的,而且是為每條連線維護獨立的值,也即,某條連線呼叫last_insert_id()獲取到的值是這條連線最近一次insert操作執行後的自增值,該值不會被其它連線的sql語句所影響。這個行為保證了不同的連線能正確地獲取到它最近一次insert
sql執行所插入的行的自增值,也就是說,last_insert_id()的值不需要通過加鎖或事務機制來保證其在多連線場景下的正確性。
如果通過"insert ignore"語句嘗試插入新紀錄,假設由於unique key衝突導致插入不成功,則auto_increment計數器不會變化,根據MySQL手冊的說明,此時呼叫last_insert_id()會返回0表示沒有新行被插入。但我在MySQL
5.1.73版本上測試的結果顯示,last_insert_id()只是維持舊值而已,並不會返回0。
8. last_insert_id(expr)的行為
若呼叫last_insert_id()時傳入了引數,則它會將引數值返回給呼叫者,並記住這個值,下次呼叫不帶引數的last_insert_id()時,仍會返回這個值。可以利用這個特性實現一個多使用者安全的全域性計數器,示例如下:
1) 先建立一張表
mysql> CREATE TABLE
sequence (id INT NOT NULL);
mysql> INSERT INTO sequence VALUES (0);
2) 每條連線執行下面的SQL語句來獲取為其自動分配的全域性唯一ID
mysql> UPDATE sequence SET id=LAST_INSERT_ID(id+1);
mysql> SELECT LAST_INSERT_ID();
每次都會id+1
當然,上面給出的全域性ID分配器只是一種思路,在實際工程實現中,頻繁的update操作可能會造成系統瓶頸,可以參考PERCONA
MYSQL PERFORMANCE BLOG這篇文章的優化思路(比如MySQL前面用cache抗read壓力,通過delay update來減緩update壓力)。
參考: