1. 程式人生 > >mysql LAST_INSERT_ID 使用與注意事項

mysql LAST_INSERT_ID 使用與注意事項

在使用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壓力)。 參考: