
pdo::lastinsertid() 方法用于返回最后插入的行的id,前提是该表的主键是自增类型(如 auto_increment)。它的关键之处在于,它只能在生成该id的同一个数据库会话中正确获取到。这意味着,如果您在一个数据库会话中执行了 insert 操作,然后在另一个新的数据库会话中尝试调用 lastinsertid(),它将无法获取到之前会话生成的id,通常会返回 0。
在许多不当的实现中,开发者可能会在每次需要执行数据库操作时,都调用一个方法来创建一个全新的数据库连接。以下是导致 lastInsertId() 返回 0 的典型代码结构:
class Db {
private $host = "localhost";
private $user = "root";
private $pwd = "";
private $dbName = "cms";
public function connect() {
// 每次调用都会创建一个新的 PDO 实例
$dsn = 'mysql:host=' . $this->host . ';dbname=' . $this->dbName;
$pdo = new PDO($dsn, $this->user, $this->pwd);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
return $pdo;
}
}
class Jobs extends Db {
public function addJob($job_date_time, $job_type, $job_decs) {
$sql = "INSERT INTO jobs(job_date_time, job_type, job_decs) VALUES (?, ?, ?)";
// 第一次调用 connect(),创建连接 A
$stmt = $this->connect()->prepare($sql);
$stmt->execute([$job_date_time, $job_type, $job_decs]);
// 第二次调用 connect(),创建连接 B (与连接 A 是不同的会话)
$lastId = $this->connect()->lastInsertId();
echo $lastId; // 此时 lastId 将返回 0
}
}在上述代码中,Jobs 类的 addJob 方法内部,$this-youjiankuohaophpcnconnect()->prepare($sql) 会创建一个 PDO 实例(假设为连接 A),并执行 INSERT 操作。紧接着,$this->connect()->lastInsertId() 又会再次调用 connect() 方法,从而创建了一个全新的 PDO 实例(假设为连接 B)。由于 lastInsertId() 是在连接 B 上被调用的,而 INSERT 操作是在连接 A 上执行的,连接 B 对连接 A 中发生的插入操作一无所知,因此 lastInsertId() 返回 0。
为了解决这个问题,我们需要确保在整个请求生命周期内,Db 类只创建并复用一个 PDO 数据库连接实例。这可以通过在 Db 类中存储已创建的 PDO 实例,并在后续调用时返回该实例来实现,这是一种简单的单例模式实现方式。
以下是优化后的 Db 类示例:
立即学习“PHP免费学习笔记(深入)”;
<?php
class Db {
private $host = "localhost";
private $user = "root";
private $pwd = "";
private $dbName = "cms";
private $pdo; // 用于存储 PDO 实例的属性
public function connect() {
// 检查 $this->pdo 是否已经存在连接实例
if (!$this->pdo) {
// 如果不存在,则创建新的 PDO 连接
$dsn = 'mysql:host=' . $this->host . ';dbname=' . $this->dbName;
try {
$this->pdo = new PDO($dsn, $this->user, $this->pwd);
$this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 设置错误模式为抛出异常
} catch (PDOException $e) {
// 捕获连接错误,可以记录日志或抛出自定义异常
die("数据库连接失败: " . $e->getMessage());
}
}
// 返回已存在的或新创建的 PDO 实例
return $this->pdo;
}
}
class Jobs extends Db {
public function addJob($job_date_time, $job_type, $job_decs) {
$pdoInstance = $this->connect(); // 获取共享的 PDO 实例
$sql = "INSERT INTO jobs(job_date_time, job_type, job_decs) VALUES (?, ?, ?)";
$stmt = $pdoInstance->prepare($sql);
$stmt->execute([$job_date_time, $job_type, $job_decs]);
// 在同一个 PDO 实例上调用 lastInsertId()
$lastId = $pdoInstance->lastInsertId();
echo $lastId;
}
}
// 示例用法
$jobs = new Jobs();
$job_date_time = "2021-11-11T11:40";
$job_type = "Test Type";
$job_desc = "Test Desc";
$jobs->addJob($job_date_time, $job_type, $job_desc);
?>lastInsertId() 返回 0 的问题,通常是由于对数据库连接生命周期管理不当所致。通过在数据库连接类中实现简单的单例模式,确保在应用程序的整个请求生命周期内复用同一个 PDO 实例,可以有效解决此问题,并提升数据库操作的效率和稳定性。正确管理数据库连接是编写健壮和高性能 PHP 应用程序的关键一环。
以上就是深入理解 PHP PDO:正确获取最后插入ID的连接管理策略的详细内容,更多请关注php中文网其它相关文章!
PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号