PDO的lastInsertId()方法总是返回0

21

我遇到了一个问题。我的框架在 PHP 5.3.0 中运行得非常好。我将 PHP 版本升级到 PHP 5.4.x 后,发现我的框架的某些部分出现了一些问题。

PHP 版本升级后,PDO lastInsterId() 总是返回 0

我有一个名称为 id 的自增字段。它可以正常地向数据库添加数据。

由于某些原因,我始终无法获取最后插入的 id,而会得到 0。

这是我的代码:

databaseobjects.php

public static function create () {
        global $db;
        $attributes = self::sanitize(static::$fields);

        $sql  = "INSERT INTO ".PREFIX.static::$table_name." (";
        $sql .= join(", ", array_keys($attributes));
        $sql .= ") VALUE (:";
        $sql .= join(", :", array_keys($attributes));
        $sql .= ")";

        return ($db->crudQuery($sql, $attributes)) ? true : false;
    }

public static function lastInsertID () {
        global $db;
        return $db->handler->lastInsertId();
    }

database.php

public function crudQuery($sql, $data) {
        $sth = $this->handler->prepare($sql);
        return $sth->execute($data);
    }

首先调用create()方法,然后调用crudQuery()方法。 如我之前所述,我可以成功地将数据添加到MySQL数据库中。 遗憾的是,当我调用lastInsterID()方法时,它总是返回0。

如果你能在我用SQL查询获取最后一个ID之前帮我解决这个问题,我将不胜感激(:


我注意到你的方法定义中有static关键字。你是如何调用这些方法的? - Pekka
数据库中的每个表都有一个类(如果没有表的类,我的框架会自动生成它们)。每个数据库表类都扩展到 databaseobjects.php。这样,在编码时我就不会重复自己。 - Revenant
2
请记住,lastInsertId() 是针对 连接 而不是 的唯一标识符 - 在调用 create()lastInsertID() 之间是否执行了其他数据库查询?还要注意,如果在事务中执行查询并在 COMMIT 后查询 id,则 lastInsertId() 报告 0 - DaveRandom
我已经仔细检查了我的查询,并且在运行lastInsertID()方法之前正确地运行了INSERT查询。我还尝试过return $db->handler->lastInsertId('id');,但没有成功。 - Revenant
5个回答

26
除了php/PDO或您的框架中的错误之外,还有两种可能性。一种是在与插入不同的MySQL连接上调用lastInsertId(),另一种是在应用程序/框架中生成id并插入它,而不是让auto_increment为您生成它。表中哪一列是主键/auto_increment?这个列是否包含在$attributes中的create()函数中?
您可以使用以下代码测试PDO以确保该部分正确工作(在新文件中):
// Replace the database connection information, username and password with your own.
$conn = new PDO('mysql:dbname=test;host=127.0.0.1', 'user', 'password');

$conn->exec('CREATE TABLE testIncrement ' .
            '(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50))');
$sth = $conn->prepare('INSERT INTO testIncrement (name) VALUES (:name)');
$sth->execute([':name' => 'foo']);
var_dump($conn->lastInsertId());
$conn->exec('DROP TABLE testIncrement');

我运行这个脚本时,输出如下:

string(1) "1"

是的,它被包含在内,但作为NULL,因此MySQL正在分配ID值。在所有我的数据库表中,主键/自动增量的列名都叫做“id”。我刚刚仔细检查了SQL查询,并且正确的INSERT是在调用lastInsertID()方法之前运行的最后一个查询。 - Revenant
我忘了在我的框架中提到查询不包括NULL值。只有当我使用var_dump()函数时,才能看到相关表的所有列(如果没有分配值,则显示该列的值为NULL)。 - Revenant
我添加了示例代码来测试这是否是PDO问题还是您的应用程序/框架问题。 - Gary G
感谢您的帮助。我已经编写了类似的代码示例来测试PDO,但仍然得到“0”。我将尝试重新安装XAMPP。但是,在我的服务器上,我的框架和代码示例(我的和你的)都能正常工作。 - Revenant
我正在使用一个函数初始化pdo连接。因此,当我调用lastInsertID()时,它会创建一个新的连接。谢谢。 - MichaelTheDev
显示剩余2条评论

10

在提交事务之后,PDO::lastInsertID()将返回0,因此最好在事务提交之前调用此方法。


1
这是正确的答案。 - Rouzbeh Zarandi
我在想为什么它总是返回0。后来,检查代码让我明白我正在使用事务。 - Wolverine

2

另一个问题可能是使用 $pdo->exec($sql) 而不是 $pdo->query($sql)。

当你使用 $pdo->lastInsertId() 时,exec($sql) 总是会返回 0。因此,请改用 query()。


1

由于外键约束,最后一个插入语句失败,我得到了0分。last_error是一个字符串。


是的,这也是我的错误。我没有意识到查询失败了。如果你遇到这个问题,请检查你的查询! - dns_nx

1

这正是我的问题所在。我使用了你的解决方案解决了它。感谢分享! - Devner

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