"PDO::lastInsertId" / "mysql_insert_id" 的替代方案

6

我经常听到使用"lastInsertId"(如果您不使用PDO,则使用mysql_insert_id())是有害的。在触发器的情况下,显然是这样,因为它可能返回完全不是INSERT创建的最后一个ID。

$DB->exec("INSERT INTO example (column1) VALUES ('test')");
// Usually returns your newly created ID.
// However when a TRIGGER inserts into another table with auto-increment:
// -> Returns newly created ID of trigger's INSERT
$id = $DB->lastInsertId();

有什么替代方案吗?

6个回答

4

在我看来,它被认为是“邪恶”的原因只是因为几乎没有其他SQL数据库(如果有的话)具备它。

就个人而言,我发现它非常有用,并且希望在其他系统上不必采用更复杂的方法。


至少MSSQL有相同的功能。在我以前的工作中,使用“插入ID”曾经导致了重大问题,当有人向表添加触发器时,整个网站就会崩溃 - 对于那些不知道该触发器的人来说,这没有明显的原因... - BlaM

3

一种替代方法是使用序列,因此在插入之前自己生成ID。

不幸的是,MySQL不支持它们,但是像Adodb这样的库可以使用另一个表来模拟它们。然而,我认为模拟本身将使用lastInsertId()或等效函数...但至少你不太可能在仅用于序列的表上有触发器。


2
如果您选择使用ADOdb(http://adodb.sourceforge.net/),那么您可以事先创建插入ID,并在插入时明确指定ID。这种方法可以实现可移植性(ADOdb支持许多不同的数据库...),并确保您使用了正确的插入ID。
PostgreSQL SERIAL数据类型类似,只是它是针对每个表/序列的,您在请求时指定要获取最后一个插入ID的表/序列。

看起来非常有趣。这种技术对性能有什么影响? - BlaM
2
是的,但如果你被迫使用PDO,你会怎么做? - Elijah
你可以编写自己的代码来完成ADOdb所做的事情,只不过使用PDO。你最终会得到一个单独的表来存储序列,在获取新ID时,你需要对其进行写锁定,然后再增加序列值。 - Keith Palmer Jr.
它不应该对性能产生太大影响,它只是一个非常简单的表格,被锁定,获取单个记录,增加,解锁。我在使用它的任何应用程序中都没有注意到任何性能差异。记住:先让它正常工作,稍后再调整性能。 - Keith Palmer Jr.

1

我猜这也不算是最先进的方法,但我使用写锁确保我真正获取到了最后插入的ID。


显然也可以工作 - 但在高性能Web应用程序中,我认为锁定更加恶劣... - BlaM

0

虽然不够复杂也不够高效,但如果您插入的数据包含唯一字段,则SELECT显然可以产生您想要的结果。

例如:

INSERT INTO example (column1) VALUES ('test');
SELECT id FROM example WHERE column1 = 'test';

显然 ;) - 但也显然相当丑陋 ;) - BlaM

-3
你可以尝试这个:
$sql = "SELECT id FROM files ORDER BY id DESC LIMIT 1";
$PS = $DB -> prepare($sql);
$PS -> execute();
$result = $PS -> fetch();

3
在高流量环境中,这不是一种可行的选择。你会经常获取错误的ID。 - BlaM

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接