MySQL學習筆記(四):MySQL中LAST_INSERT_ID()使用時的注意事項

主要參考博客(一些內容照搬了):
- http://zhaohe162.blog.163.com/blog/static/38216797201122411193745/
- http://blog.csdn.net/slvher/article/details/42298355
- http://www.jquerycn.cn/a_14138


關於LAST_INSERT_ID()

LAST_INSERT_ID()是MySQL中的一個函數,自動返回最後一個INSERTUPDATE查詢中AUTO_INCREMENT列設置的第一個表發生的值。


注意事項


① 查詢和插入所使用的Connection對象必須是同一個纔可以,否則返回值是不可預料的;

使用這函數向一個給定Connection對象返回的值是該Connection對象產生對影響AUTO_INCREMENT列的最新語句第一個AUTO_INCREMENT值的。這個值不能被其它Connection對象的影響,即它們產生它們自己的AUTO_INCREMENT值。


LAST_INSERT_ID() 是與table無關的,如果向表a插入數據後,再向表b插入數據,LAST_INSERT_ID()返回表b中的ID值;

即我們使用LAST_INSERT_ID()時返回的ID值時當前對象操作的最後一張表時所返回的ID值。

mysql> INSERT user_info(username,password,age,sex) VALUES('BBB',md5('B'),25,0);

mysql> SELECT * FROM user_info;
+----+----------+----------------------------------+------+-----+
| id | username | password                         | age  | sex |
+----+----------+----------------------------------+------+-----+
|  1 | AAA      | 7fc56270e7a70fa81a5935b72eacbe29 |   20 |   1 |
|  2 | BBB      | 9d5ed678fe57bcca610140957afab571 |   25 |   0 |
+----+----------+----------------------------------+------+-----+
2 rows in set (0.00 sec)

mysql> SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                2 |
+------------------+
1 row in set (0.00 sec)

mysql> CREATE TABLE grade(
    -> id SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    -> subjectname VARCHAR(30) NOT NULL,
    -> grade TINYINT UNSIGNED NOT NULL
    -> );
Query OK, 0 rows affected (0.03 sec)

mysql> INSERT grade(subjectname,grade) VALUES('Math',95);
Query OK, 1 row affected (0.01 sec)

mysql> SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                1 |
+------------------+
1 row in set (0.00 sec)

③ 使用一條INSERT語句同時插入多個行的數據時, LAST_INSERT_ID() 只返回插入的第一行數據時產生的值。

這個應該算是一個易忽視的地方,我在剛開始使用LAST_INSERT_ID()這個函數時就犯了錯。返回的是多行數據中第一行數據的ID
如此設定的原因是,這使依靠其它服務器複製同樣的 INSERT語句變得簡單。

mysql> SELECT * FROM user_info;
+----+----------+----------------------------------+------+-----+
| id | username | password                         | age  | sex |
+----+----------+----------------------------------+------+-----+
|  1 | AAA      | 7fc56270e7a70fa81a5935b72eacbe29 |   20 |   1 |
|  2 | BBB      | 9d5ed678fe57bcca610140957afab571 |   25 |   0 |
+----+----------+----------------------------------+------+-----+
2 rows in set (0.00 sec)

mysql> INSERT user_info(username,password,age,sex) VALUES('CCC',md5('C'),24,1),('DDD',md5('D'),22,0);
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM user_info;
+----+----------+----------------------------------+------+-----+
| id | username | password                         | age  | sex |
+----+----------+----------------------------------+------+-----+
|  1 | AAA      | 7fc56270e7a70fa81a5935b72eacbe29 |   20 |   1 |
|  2 | BBB      | 9d5ed678fe57bcca610140957afab571 |   25 |   0 |
|  3 | CCC      | 0d61f8370cad1d412f80b84d143e1257 |   24 |   1 |
|  4 | DDD      | f623e75af30e62bbd73d6df5b50bb7b5 |   22 |   0 |
+----+----------+----------------------------------+------+-----+
4 rows in set (0.00 sec)

mysql> SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                3 |
+------------------+
1 row in set (0.00 sec)

LAST_INSERT_ID()如何保證其正確性

LAST_INSERT_ID()的值是由MySQL server來維護的,而且是爲每條連接維護獨立的值,也即,某條連接調用LAST_INSERT_ID()獲取到的值是這條連接最近一次INSERT操作執行後的自增值,該值不會被其它連接的SQL語句所影響。這個行爲保證了不同的連接能正確地獲取到它最近一次INSERT SQL執行所插入的行的自增值,也就是說,LAST_INSERT_ID()的值不需要通過加鎖或事務機制來保證其在多連接場景下的正確性。


⑤ 假如你使用 INSERT IGNORE而記錄被忽略,則AUTO_INCREMENT 計數器不會增量,而 LAST_INSERT_ID() 返回0, 這反映出沒有插入任何記錄。

一般情況下獲取剛插入的數據的ID,使用SELECT max(id) FROM table 是可以的。但在多線程情況下,就不行了。在多用戶交替插入數據的情況下max(id)顯然不能用。這就該使用LAST_INSERT_ID了,因爲LAST_INSERT_ID是基於Connection的,只要每個線程都使用獨立的Connection對象,LAST_INSERT_ID函數將返回該ConnectionAUTO_INCREMENT列最新的INSERT or UPDATE操作生成的第一個recordIDLAST_INSERT_ID是基於單個connection的, 不可能被其它的客戶端連接改變。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章