主要參考博客(一些內容照搬了):
- 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中的一個函數,自動返回最後一個INSERT
或UPDATE
查詢中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
函數將返回該Connection
對AUTO_INCREMENT
列最新的INSERT or UPDATE
操作生成的第一個record
的ID
。LAST_INSERT_ID
是基於單個connection
的, 不可能被其它的客戶端連接改變。