在 MySQL 中,LAST_INSERT_ID(), LAST_INSERT_ID(expr) 函数可以用来返回最后一个 INSERT 语句的 AUTOINCREMENT 列的值。
LAST_INSERT_ID 函数在没有参数的情况下,返回一个 BIGINT UNSIGNED(64 位)值,表示作为最近执行的 INSERT 语句的结果为 AUTO_INCREMENT 列成功插入的第一个自动生成的值。如果没有成功插入行,则 LAST_INSERT_ID() 的值保持不变。
使用参数带有参数的 LAST_INSERT_ID 函数,则返回一个无符号整数。
假如您使用一个语句生成 AUTO_INCREMENT 值,然后在多行 INSERT 语句中引用 LAST_INSERT_ID(),该语句将行插入到具有自己的 AUTO_INCREMENT 列的表中。LAST_INSERT_ID() 的值在第二条语句中保持稳定;它对第二行和后面的行的值不受早期行插入的影响。但是,如果您混合对 LAST_INSERT_ID() 和 LAST_INSERT_ID(expr) 的引用,则效果未定义。
如果前面的语句返回错误,则 LAST_INSERT_ID() 的值未定义。对于事务表,如果语句由于错误而回滚,则 LAST_INSERT_ID() 的值未定义。对于手动 ROLLBACK,LAST_INSERT_ID() 的值不会恢复到事务之前的值;它保持在回滚点的状态。
在存储例程(过程或函数)或触发器的主体内,LAST_INSERT_ID() 的值更改方式与在这些类型的对象主体之外执行的语句相同。 以下语句看到的存储例程或触发器对 LAST_INSERT_ID() 值的影响取决于例程的类型:
如果存储过程执行更改 LAST_INSERT_ID() 值的语句,则更改后的值会被过程调用之后的语句看到。
对于更改值的存储函数和触发器,该值会在函数或触发器结束时恢复,因此它们后面的语句不会看到更改的值。
生成的 ID 在每个连接的基础上维护在服务器中。这意味着函数返回给给定客户端的值是为影响该客户端的 AUTO_INCREMENT 列的最新语句生成的第一个 AUTO_INCREMENT 值。此值不受其他客户端的影响,即使它们生成自己的 AUTO_INCREMENT 值。 这种行为确保每个客户端都可以检索自己的 ID,而不用担心其他客户端的活动,也不需要锁或事务。
如果将行的 AUTO_INCREMENT 列设置为非“魔术”值(即非 NULL 且非 0 的值),则不会更改 LAST_INSERT_ID() 的值。
如果使用单个 INSERT 语句插入多行,则 LAST_INSERT_ID() 仅返回为第一个插入行生成的值。这样做的原因是可以轻松地针对其他服务器重现相同的 INSERT 语句。
(1)使用 LAST_INSERT_ID 函数返回最后一个 INSERT 语句 AUTO_INCREMENT 列的值,如下:
mysql> insert t_test(name) values('name1'),('name2'),('name3'); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> select LAST_INSERT_ID(); +------------------+ | LAST_INSERT_ID() | +------------------+ | 4 | +------------------+ 1 row in set (0.04 sec) mysql> select * from t_test; +----+-------+ | id | name | +----+-------+ | 4 | name1 | | 5 | name2 | | 6 | name3 | +----+-------+ 3 rows in set (0.04 sec)
由运行结果可知,上面 insert 语句一次性向 t_test 表插入3条记录。id 字段分别为 4、5 和 6,而 LAST_INSERT_ID 函数返回的值为 4。表明当前执行的 INSERT 语句不影响 LAST_INSERT_ID() 的值。
(2)如果您使用 INSERT IGNORE 并忽略该行,则 LAST_INSERT_ID() 与当前值保持不变(如果连接尚未执行成功的 INSERT,则返回 0),并且对于非事务性表,AUTO_INCREMENT 计数器不递增。 对于 InnoDB 表,如果 innodb_autoinc_lock_mode 设置为 1 或 2,则 AUTO_INCREMENT 计数器会递增,如以下示例所示:
mysql> USE test; mysql> SELECT @@innodb_autoinc_lock_mode; +----------------------------+ | @@innodb_autoinc_lock_mode | +----------------------------+ | 1 | +----------------------------+ mysql> CREATE TABLE `t` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `val` INT(11) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `i1` (`val`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; # Insert two rows mysql> INSERT INTO t (val) VALUES (1),(2); # With auto_increment_offset=1, the inserted rows # result in an AUTO_INCREMENT value of 3 mysql> SHOW CREATE TABLE t\G *************************** 1. row *************************** Table: t Create Table: CREATE TABLE `t` ( `id` int(11) NOT NULL AUTO_INCREMENT, `val` int(11) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `i1` (`val`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 # LAST_INSERT_ID() returns the first automatically generated # value that is successfully inserted for the AUTO_INCREMENT column mysql> SELECT LAST_INSERT_ID(); +------------------+ | LAST_INSERT_ID() | +------------------+ | 1 | +------------------+ # The attempted insertion of duplicate rows fail but errors are ignored mysql> INSERT IGNORE INTO t (val) VALUES (1),(2); Query OK, 0 rows affected (0.00 sec) Records: 2 Duplicates: 2 Warnings: 0 # With innodb_autoinc_lock_mode=1, the AUTO_INCREMENT counter # is incremented for the ignored rows mysql> SHOW CREATE TABLE t\G *************************** 1. row *************************** Table: t Create Table: CREATE TABLE `t` ( `id` int(11) NOT NULL AUTO_INCREMENT, `val` int(11) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `i1` (`val`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 # The LAST_INSERT_ID is unchanged because the previous insert was unsuccessful mysql> SELECT LAST_INSERT_ID(); +------------------+ | LAST_INSERT_ID() | +------------------+ | 1 | +------------------+
(3)如果 expr 作为 LAST_INSERT_ID() 的参数给出,则参数的值由函数返回,并作为 LAST_INSERT_ID() 返回的下一个值被记住。这可以用来模拟序列:
a、创建一个表来保存序列计数器并对其进行初始化:
mysql> CREATE TABLE sequence (id INT NOT NULL); mysql> INSERT INTO sequence VALUES (0);
b、使用该表生成序列号,如下所示:
mysql> UPDATE sequence SET id=LAST_INSERT_ID(id+1); mysql> SELECT LAST_INSERT_ID();
UPDATE 语句递增序列计数器并导致对 LAST_INSERT_ID() 的下一次调用返回更新的值。 SELECT 语句检索该值。 mysql_insert_id() C API 函数也可用于获取值。 请参阅 mysql_insert_id()。
您可以在不调用 LAST_INSERT_ID() 的情况下生成序列,但是以这种方式使用该函数的效用是 ID 值在服务器中作为最后自动生成的值进行维护。 它是多用户安全的,因为多个客户端可以发出 UPDATE 语句并使用 SELECT 语句(或 mysql_insert_id())获取自己的序列值,而不会影响或被其他生成自己的序列值的客户端影响。
请注意,mysql_insert_id() 仅在 INSERT 和 UPDATE 语句之后更新,因此在执行 SELECT 或 SET 等其他 SQL 语句后,您不能使用 C API 函数检索 LAST_INSERT_ID(expr) 的值。