LAST_INSERT_ID(), LAST_INSERT_ID(expr)

原文:https://dev.mysql.com/doc/refman/5.5/en/query-cache-configuration.html

使用不带参数的LAST_INSERT_ID将返回第一个insert对应AUTO_INCREMENT字段的值,从MySQL 5.5.29开始该值返回为BIGINT UNSIGNED,以前的版本返回BIGINT (signed) 。如果insert执行成功但没有数据插入,则LAST_INSERT_ID返回值不变。

在MySQL 5.5.29中带参数的LAST_INSERT_ID()返回值类型为无符号整型,以前的版本返回整型。

例如:在插入一条数据后AUTO_INCREMENT字段会生成一个值,你可以使用下面的SQL拿到这个值:

mysql> SELECT LAST_INSERT_ID();
        -> 195

当前正在执行的语句并不能影响LAST_INSERT_ID()的返回值。假如你通过一个语句生成了AUTO_INCREMENT的值,此时执行LAST_INSERT_ID()获取到一个值,然后执行一条插入多行数据的INSERT语句,该语句设置了AUTO_INCREMENT列的值,再次通过LAST_INSERT_ID()获取的值与前一次相同。(无论使用LAST_INSERT_ID()还是LAST_INSERT_ID(expr),都不会起效)

如果前一个语句产生了错误,通过LAST_INSERT_ID()获取的值是undefined.在事务中,如果一个语句执行错误并回滚,LAST_INSERT_ID()值将是undefined.未产生异常的回滚中(手工回滚),LAST_INSERT_ID()的值将是事务中最后一个AUTO_INCREMENT的值,而不会重置为事务开始前的初始值。

在MySQL 5.5.35前,使用MySQL 5.5.35过滤规则的函数不能获取正确的值。(Bug #17234370, Bug #69861)

在stored routine (存储过程或函数)或触发器(trigger)的方法体中,LAST_INSERT_ID()值的变化规则与在方法体外执行的规则一致。在routine执行完毕后,routine类型不同对LAST_INSERT_ID()值也会不同:

  • 如果一个存储过程执行完后改变了LAST_INSERT_ID()的值,接下来执行的存储过程能够获取到这个值.

  • 在存储函数和触发器中改了LAST_INSERT_ID值的话,在方法体执行完毕后LAST_INSERT_ID()的值会被重置,所以后续的语句将不能获取到这个值。

在服务器端基于每一个连接维护了一个对应的ID(LAST_INSERT_ID的结果)值。这意味着调用LAST_INSERT_ID()将返回这个连接产生的最后一个AUTO_INCREMENT值,并不会影响其它连接使用该函数的返回值,即使其它连接也生成了AUTO_INCREMENT的值。这个行为确保了每个客户端能够获取自己生成AUTO_INCREMENT的值,而不用关心其它客户端对AUTO_INCREMENT的值的影响,也不用使用锁或者是事务。

如果你将AUTO_INCREMENT列的值设为非“magic”(非NULL和0)的值,LAST_INSERT_ID()的值将不会变。

重要
如果你在一个INSERT语句中插入多条数据,LAST_INSERT_ID()只会获取一个插入行的值。原因是为了将INSERT语句尽量简单。

For example:

mysql> USE test;
Database changed
mysql> CREATE TABLE t (
    ->   id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
    ->   name VARCHAR(10) NOT NULL
    -> );
Query OK, 0 rows affected (0.09 sec)

mysql> INSERT INTO t VALUES (NULL, 'Bob');
Query OK, 1 row affected (0.01 sec)

mysql> SELECT * FROM t;
+----+------+
| id | name |
+----+------+
|  1 | Bob  |
+----+------+
1 row in set (0.01 sec)

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

mysql> INSERT INTO t VALUES
    -> (NULL, 'Mary'), (NULL, 'Jane'), (NULL, 'Lisa');
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM t;
+----+------+
| id | name |
+----+------+
|  1 | Bob  |
|  2 | Mary |
|  3 | Jane |
|  4 | Lisa |
+----+------+
4 rows in set (0.01 sec)

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

尽管第二条INSERT语句成功插入了三条数据,但是ID却是指向本次插入的第一行数据2.

如果你使用了INSERT IGNORE并且插入行被忽略,LAST_INSERT_ID()的值将不变(如果这个连接尚未成功插入数据返回值将为0),在非事务操作中,AUTO_INCREMENT计数器将不增长。在InnoDB表中,innodb_autoinc_lock_mode的值如果是1或2,AUTO_INCREMENT计数器将增长,下面举一个例子:

mysql> USE test;
Database changed

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

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;
Query OK, 0 rows affected (0.02 sec)

-- Insert two rows

mysql> INSERT INTO t (val) VALUES (1),(2);
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

-- 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=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

-- 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 |
+------------------+
1 row in set (0.00 sec)

-- 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=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

-- The LAST_INSERT_ID is unchanged becuase the previous insert was unsuccessful

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

更多信息查看14.11.6, “AUTO_INCREMENT Handling in InnoDB”

如果LAST_INSERT_ID()的参数是一个表达式,返回值就是表达式的结果,也是LAST_INSERT_ID()的值。我们使用下面的步骤模拟这一过程:

  1. Create a table to hold the sequence counter and initialize it:

    mysql> CREATE TABLE sequence (id INT NOT NULL);
    mysql> INSERT INTO sequence VALUES (0);
    
  2. Use the table to generate sequence numbers like this:

        
        
    mysql> UPDATE sequence SET id=LAST_INSERT_ID(id+1); mysql> SELECT LAST_INSERT_ID();

    The UPDATE statement increments the sequence counter and causes the next call to LAST_INSERT_ID() to return the updated value. The SELECT statement retrieves that value. The mysql_insert_id() C API function can also be used to get the value. See Section 23.8.7.37, “mysql_insert_id()”.

You can generate sequences without calling LAST_INSERT_ID(), but the utility of using the function this way is that the ID value is maintained in the server as the last automatically generated value. It is multi-user safe because multiple clients can issue the UPDATE statement and get their own sequence value with the SELECT statement (or mysql_insert_id()), without affecting or being affected by other clients that generate their own sequence values.


Note that  mysql_insert_id()  is only updated after  INSERT  and  UPDATE  statements, so you cannot use the C API function to retrieve the value for  LAST_INSERT_ID(expr)  after executing other SQL statements like  SELECT  or  SET .
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值