您的位置:首页 > 数据库 > MySQL

LAST_INSERT_ID(), LAST_INSERT_ID(expr)

2017-02-06 16:04 411 查看
原文: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> [code]SELECT LAST_INSERT_ID();

-> 195
[/code]

当前正在执行的语句并不能影响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> [code]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)
[/code]

尽管第二条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()的值。我们使用下面的步骤模拟这一过程:

Create a table to hold the sequence counter and initialize it:
mysql> [code]CREATE TABLE sequence (id INT NOT NULL);

mysql>
INSERT INTO sequence VALUES (0);

[/code]

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
.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  mysql sql last_insert_id