MySql的LAST_INSERT_ID()函数是否保证正确?


36

当我对具有列INSERT的表进行单行处理时,AUTO_INCREMENT我想使用该LAST_INSERT_ID()函数返回AUTO_INCREMENT为该行存储的新的'ed值。

由于许多Microsoft SQL Server的开发者和管理员毫无疑问都知道在SQL Server(等效功能SCOPE_IDENTITY@@IDENTITY)一直没有没有问题

我知道MySQL文档状态:

生成的ID在每个连接的服务器中维护。这意味着函数返回给定客户端的AUTO_INCREMENT是为该客户端影响AUTO_INCREMENT最新语句生成的第一个值。该值不会受到其他客户端的影响,即使它们生成AUTO_INCREMENT自己的值也是如此。此行为可确保每个客户端都可以检索自己的ID,而不必担心其他客户端的活动,也不需要锁或事务。

(资源)

甚至甚至说:

从多个客户端同时使用LAST_INSERT_ID()AUTO_INCREMENT列是完全有效的。

(资源)

是否存在任何可能导致LAST_INSERT_ID()无法返回正确值的已知风险或情况?

我在CentOS 5.5 x64和Fedora 16 x64和InnoDB引擎上使用MySQL 5.5。

Answers:


35

在使用时,我想指出几个警告LAST_INSERT_ID

  1. 我知道您提到了单行插入。但是,当执行多行插入时,LAST_INSERT_ID()将返回插入的第一行(而不是最后一行)的值。

  2. 如果插入失败,LAST_INSERT_ID()则将是不确定的。对于事务的自动回滚(由于错误)也是如此。

  3. 如果您在成功的事务中执行插入操作,并且仍然发出ROLLBACKLAST_INSERT_ID()则会保留回滚之前的状态。

  4. 在基于语句的复制中和使用基于语句的复制时,有一些警告。第一个是在触发器或函数中使用时。第二种是不太常见的方案,其中auto_increment列是复合主键的一部分,而不是键中的第一列。AUTO_INCREMENTLAST_INSERT_ID


7

为了进一步扩展DTest给出的答案中的第2点:

在我使用的MySQL版本上,最好在计划执行插入的每个代码块之前显式重置LAST_INSERT_ID的值。

可以这样完成:

-- initialize the LAST_INSERT_ID to some flag value:
SELECT LAST_INSERT_ID( some_flag_init_value_of_your_choice );
-- perform the insert  
INSERT INTO ttt (ccc) VALUES (vvv);
-- retrieve the id of the inserted row:  
SELECT LAST_INSERT_ID();

执行上述一系列语句后,通过检查执行结束时LAST_INSERT_ID是否仍设置为“ some_flag_init_value_of_your_choice”,您将知道插入是否有任何影响。

否则,您可能会遇到以下问题:

INSERT INTO ttt ( ccc ) VALUES ( 'a' );    -- assume this succeeds.
SELECT LAST_INSERT_ID();                   -- this will return the unique id of the new row with value 'a'.
INSERT INTO ttt ( ccc ) VALUES ( 'b' );    -- assume this FAILS.
SELECT LAST_INSERT_ID();                   -- this will STILL RETURN the unique id of the row with 'a'.

因为第二次插入失败,所以您可能一直期望对LAST_INSERT_ID的第二次调用将返回NULL或将产生空结果集(零行)。它仍然返回有效的整数标识符的事实可能使您误以为第二个插入未成功时将成功。

当您考虑到LAST_INSERT_ID将继续保留并重复上一个成功的唯一ID时,事情就变得更加奇怪了,即使随后失败的插入语句针对的是产生上一个成功的唯一ID的表不同的表。换句话说,您插入表TA并获得ID 5,然后插入TB(但失败),但仍然看到5。基于此,您认为您刚刚在TA中创建了新行。 ID为5 TB中ID为5的新行,而实际上,要么在ID为5的TB中不存在任何行,要么存在这样的行,但实际上它与您仅使用的任何代码无关跑了


2
首先,您不应该使用的存在last_insert_id()来判断查询是否成功。毕竟,这是最后插入的ID,当您已经知道成功时,将保留您需要的值。
Pacerier
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.