Kev*_*Kev 39 mysql auto-increment
当我对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。
Der*_*ney 37
使用时我想指出的几个警告LAST_INSERT_ID:
我知道你提到了单行插入。但是在进行多行插入时,LAST_INSERT_ID()将返回插入的第一行(而不是最后一行)的值。
如果插入失败,LAST_INSERT_ID()则未定义。对于事务的自动回滚(由于错误)也是如此。
如果您在成功的事务中执行插入操作,并且您仍然发出ROLLBACK,LAST_INSERT_ID()将保持回滚之前的状态。
有一对夫妇的注意事项使用时AUTO_INCREMENT和LAST_INSERT_ID基于语句的复制。第一个是在触发器或函数中使用时。第二种是不太常见的情况,其中您的 auto_increment 列是复合主键的一部分,而不是键中的第一列。
要进一步扩展 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();
Run Code Online (Sandbox Code Playgroud)
执行完上述系列语句后,通过检查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'.
Run Code Online (Sandbox Code Playgroud)
因为第二次插入失败,您可能一直期望对 LAST_INSERT_ID 的第二次调用要么返回 NULL,要么会产生一个空的结果集(零行)。它仍然返回一个有效的整数标识符这一事实可能会误导您认为第二次插入 SUCCEEDED 而它没有成功。
当您考虑到 LAST_INSERT_ID 将继续保留并重复最后一个成功的唯一 id 时,即使后续失败的插入语句针对与生成最后一个成功唯一 id 的表不同的表,事情也会变得更加奇怪。换句话说,你插入到表 TA 并得到 5 的 id,然后你插入到 TB(但它失败了),但你仍然看到一个 5。基于此,你认为你刚刚在 TA 中创建了一个新行id 为 5 , TB 中的新行 id 为 5,而实际上 TB 中不存在任何 id 为 5 的行,或者确实存在这样的行,但它实际上与您刚刚编写的任何代码无关跑了。