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

许多Microsoft SQL Server开发人员和管理员无疑都知道SQL Server中的等效功能(SCOPE_IDENTITY@@IDENTITY)并非没有问题。

我知道MySQL docs的状态:


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


(源)

甚至可以说:


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

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

我在CentOS 5.5 x64和Fedora 16 x64和InnoDB引擎。

#1 楼

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


我知道您提到了单行插入。但是,当执行多行插入时,LAST_INSERT_ID()将返回插入的第一行的值(而不是最后一行)。
如果插入失败,则LAST_INSERT_ID()将不确定。自动回滚事务(由于错误)也是如此。
如果在成功的事务中执行插入操作,而您仍然发出ROLLBACK,则会保留LAST_INSERT_ID(),就像回滚之前一样。 br />在基于语句的复制中使用AUTO_INCREMENTLAST_INSERT_ID时,有一些警告。第一个是在触发器或函数中使用时。第二种是不太常见的方案,其中auto_increment列是组合主键的一部分,而不是键中的第一列。


评论


如果您有“ ON DUPLICATE KEY UPDATE”,并且在未进行任何更新的情况下也返回0,则如果您设置了一些date_field = now(),它将始终正确返回

–max4ever
19年11月25日15:59

#2 楼

为了进一步扩展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或将产生空结果集(零行)。它仍然会返回有效的整数标识符这一事实可能使您误以为第二个插入未成功时将成功。成功的唯一ID,即使随后失败的插入语句针对的表与生成最后一个成功的唯一ID的表的表不同。换句话说,您插入表TA并获得ID 5,然后插入TB(但失败),但仍然看到5。基于此,您认为您刚刚在TA中创建了新行。 ID为5且TB中ID为5的新行,而实际上,要么在ID为5的TB中不存在任何行,要么存在这样的行,但实际上与您仅使用的任何代码无关跑了。

评论


首先,您不应该使用last_insert_id()的存在来判断查询是否成功。毕竟,这是最后插入的ID,当您已经知道成功时,将保留您需要的值。

–起搏器
15年3月9日在13:45