PHP Conference Japan 2024

PDO::lastInsertId

(PHP 5 >= 5.1.0,PHP 7,PHP 8,PECL pdo >= 0.1.0)

PDO::lastInsertId 返回最后插入行的 ID 或序列值

描述

public PDO::lastInsertId(?string $name = null): string|false

返回最后插入行的 ID,或者根据底层驱动程序返回序列对象的最后一个值。例如,PDO_PGSQL 允许为 name 参数指定任何序列对象的名称。

注意:

此方法可能无法在不同的 PDO 驱动程序之间返回有意义或一致的结果,因为底层数据库甚至可能不支持自动递增字段或序列的概念。

参数

name

应从中返回 ID 的序列对象的名称。

返回值

如果没有为 name 参数指定序列名称,则 PDO::lastInsertId() 返回一个字符串,表示插入到数据库中的最后一行 的行 ID。

如果为 name 参数指定了序列名称,则 PDO::lastInsertId() 返回一个字符串,表示从指定的序列对象中检索到的最后一个值。

如果 PDO 驱动程序不支持此功能,则 PDO::lastInsertId() 将触发 IM001 SQLSTATE。

错误/异常

如果属性 PDO::ATTR_ERRMODE 设置为 PDO::ERRMODE_WARNING,则发出级别为 E_WARNING 的错误。

如果属性 PDO::ATTR_ERRMODE 设置为 PDO::ERRMODE_EXCEPTION,则抛出 PDOException

添加注释

用户贡献的注释 12 条注释

252
spark at limao dot com dot br
12 年前
请记住,如果您使用事务,则应在提交之前使用 lastInsertId
否则它将返回 0
86
toinenkayt (ta at ta) [iwonderr] gmail d
6 年前
为了节省大家的时间。

在使用 MySQL 或 MariaDB 时,如果在单个查询中插入多行(INSERT INTO table (a,b,c) VALUES (1,2,3), (2,3,4), ...)到具有 auto_increment 列的表中,PDO::lastInsertId 不会返回最后一行 的自动生成的 id。相反,它返回第一个生成的 id。这可以通过查看 MySQL 和 MariaDB 的文档来解释。

引用自各自的文档,

MySQL
"如果没有参数,LAST_INSERT_ID() 返回一个 BIGINT UNSIGNED(64 位)值,表示作为最近执行的 INSERT 语句的结果,成功插入的 AUTO_INCREMENT 列的第一个自动生成的值。"

MariaDB
"LAST_INSERT_ID()(无参数)返回作为最近执行的 INSERT 语句的结果,成功插入的 AUTO_INCREMENT 列的第一个自动生成的值。"

这显然与 lastInsertId 自身文档中所述内容不符。希望这可以帮助某些人避免调试 ID 不匹配的原因。

tl;dr (MySQL | Mariadb) + 多行插入 + PDO::lastInsertId = 第一个自动生成的 id

在运行 Windows 7 的 MariaDB 10.2.6 32 位、PHP 5.6.31 32 位和 mysqlnd 5.0.11 上测试的行为。
72
Nour
16 年前
在 mysql 中使用事务时,请注意 lastInsertId()。以下代码返回 0 而不是插入 id。

<?php
try {
$dbh = new PDO('mysql:host=localhost;dbname=test', 'username', 'password');

$stmt = $dbh->prepare("INSERT INTO test (name, email) VALUES(?,?)");

try {
$dbh->beginTransaction();
$tmt->execute( array('user', '[email protected]'));
$dbh->commit();
print
$dbh->lastInsertId();
} catch(
PDOExecption $e) {
$dbh->rollback();
print
"Error!: " . $e->getMessage() . "</br>";
}
} catch(
PDOExecption $e ) {
print
"Error!: " . $e->getMessage() . "</br>";
}
?>

如果没有抛出异常,lastInsertId 将返回 0。但是,如果在调用 commit 之前调用 lastInsertId,则会返回正确的 id。
31
dave at dtracorp dot com
18 年前
以防有人想知道
类似于

$val = 5;
$sql = "REPLACE table (column) VALUES (:val)";
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':val', $val, PDO::PARAM_INT);
$stmt->execute();
$lastId = $dbh->lastInsertId();

将返回最后插入的 id,无论记录是被替换还是仅仅被插入

REPLACE 语法,简单插入,或删除 > 插入
所以 lastInsertId() 仍然有效

请参阅 https://mysqlserver.cn/doc/refman/5.0/en/replace.html
有关 REPLACE 用法
26
warezthebeef at gmail dot com
13 年前
如果您通过 FreeTDS 从 Linux 访问 MSSQL/SQL Server 2008 R2(或更高版本),则获取最后插入 ID 的方法比下面概述的解决方案稍微简洁一些。

此处概述了相关的特定 SQL

http://msdn.microsoft.com/en-us/library/ms177564.aspx

例如,对于包含两列(product_id、product_name)的表,其中 product_id 是 uniqueidentifier 或类似的东西,您可以执行以下操作。

<?php

// 假设 $dbh 连接句柄已建立

$sql = "INSERT INTO product (product_name) OUTPUT INSERTED.product_id VALUES (?)";

$sth = $dbh->prepare($sql);

$sth->execute(array('widgets'));

$temp = $sth->fetch(PDO::FETCH_ASSOC);

?>

然后 $temp 将包含一个类似以下的数组

数组
(
[product_id] => E1DA1CB0-676A-4CD9-A22C-90C9D4E81914
)

需要注意的是,根据您选择的 TDS 版本,PDO_DBLIB/FreeTDS 在处理 uniqueidentifier 列方面存在一些问题,这些问题直到 PHP 5.3.7 才得到修复。

有关此问题和补丁的信息,请访问以下链接

https://bugs.php.net/bug.php?id=54167
12
Yonatan Ben-Nes
17 年前
需要说明的是,此函数**不**检索行的 ID(主键),而是检索其 OID。

因此,如果您使用的是最新版本的 PostgreSQL,除非您在创建表时专门向其中添加了 OID,否则此函数将无法帮助您。
17
ruben02 at hotmail dot com
13 年前
我认为在 Postgres 中,可以使用从 Postgres 8.2 版本开始提供的 RETURNING 来获取 ID,这是一个不错的解决方案。在下面的示例中,我在 insert 语句中添加了 "returning" 以及表的主键,然后在执行后,我执行了一个 fetch 操作,获取了一个包含最后插入 ID 值的数组。

<?php
public function insert($employee){

$sqlQuery = "INSERT INTO employee(user_id,name,address,city) VALUES(:user_id,:name,:address,:city) RETURNING employee_id";

$statement = $this->prepare($sqlQuery);

$a ="2002-03-11 12:01AM" ;

$statement->bindParam(":user_id", $employee->getUserId(), PDO::PARAM_INT);
$statement->bindParam(":name", $employee->getName(), PDO::PARAM_STR);
$statement->bindParam(":address", $employee->getAddress(), PDO::PARAM_STR);
$statement->bindParam(":city", $employee->getCity(), PDO::PARAM_STR);
$statement->execute();

$result = $statement->fetch(PDO::FETCH_ASSOC);
return
$result["employee_id"];

}
?>
4
enclaved
7 年前
**警告:针对 PostgreSQL 用户!** 针对 ed at hicklinslade dot com 的评论,他写道

...
$last_insert_id = $objPDO->lastInsertId("$strTable_id_seq);

此函数似乎按预期工作。我不太清楚的是,它是否只是返回序列的当前值;如果是这样,这并不是您代码刚刚插入的记录 ID 的可靠指标,尤其是在您的网站或应用程序流量非常大的情况下。
...

**切勿**在 PostgreSQL 序列中使用 lastInsertId(),**尤其是在应用程序的插入/更新负载很高时**。PostgreSQL 序列是非事务性的(一种自然的设计特性,用于避免排他性锁定,否则会导致无法接受的性能)。这意味着任何并发事务递增同一序列都会使 lastInsertId() 返回的值相对于您事务的最后一次插入无效。例如

事务 1 使用 nextval('some_seq') 插入,产生 100;
并发事务 2 使用 nextval('some_seq') 插入,产生 101;
事务 1 调用 lastInsertId(),期望得到 100,**但得到 101**。

此 PDO 方法对于 PostgreSQL 来说是愚蠢的,始终使用 INSERT ... RETURNING 代替。此致。
1
nafsinvk at gmail dot com
5 年前
$dbh->commit();
print $dbh->lastInsertId();
以上代码将始终返回零 (0)
因此,在提交事务之前调用 $dbh->lastInsertId(); 非常重要

以上代码应修改为
print $dbh->lastInsertId();
$dbh->commit();
4
noel dot mcavoy at gmail dot com
12 年前
此函数现在与更新的 MS SQL 驱动程序兼容。http://msdn.microsoft.com/en-us/library/ff628155(v=sql.105)
0
phpmanual at NOSPAM dot headbank dot co dot uk
2 年前
MySQL/MariaDB 用户请注意,尽管此函数返回字符串,但如果您的列具有 ZEROFILL 属性,则**不会保留前导零**。
0
timer timer five at gmail dot com
7 年前
关于通过类创建的连接

例如:db::SQL()->query();
然后 db::SQL()->lastInsertId();

它将创建一个新的连接,并且不会返回插入的最后一个 ID。最好包含一个 PDO 连接文件(或直接包含登录信息)并使用它来正确获取最后一个 ID。

$db = new PDO(logins);
$db->query();
$db->lastInsertId();
To Top