首页 > 解决方案 > PHP pdo lastInsertId() 总是返回一个 0

问题描述

这是数据库和PHP信息:

我在尝试使用 PHP PDO 和 MariaDB 检索最后插入的 id 以在另一个插入语句中使用时遇到问题...

很抱歉下面的伪代码含糊不清,但试图掩盖专有数据:

try {
    include_once $pdo connection stuff here;
    $pdo->beginTransaction();
    $sql = 'AN INSERT STATEMENT HERE';
    $stmt = $pdo->prepare($sql);
    $stmt->bindValue(':some_value', $some_value);
    $stmt->bindValue(':another_one', $another_one);
    $stmt->bindValue(':additional_value', $additional_value);
    $stmt->execute();
    // have tried to call $pdo->commit(): here to no avail.
     //should get the last inserted id here on the AUTO_INCREMENT column in the target table from above prepared statement
    // the AI column is not included in the insert statement above nor any value specified in the VALUES clause so should
    // set to the next available value (and does so according to peeking at row over in phpMyAdmin).
    $last_insert_id = $pdo->lastInsertId();

    // don't really want to commit the above insert here just yet in case something goes wrong below and can rollback
    // a file could be uploaded but it's not mandatory
    if (!empty($_FILES['some_file'])) { // file has been attached.
        // some file operations here
        // some file operations here
        // some file operations here
        // some file operations here
        $extensions = array("extension I am expecting");
        if (in_array($file_ext, $extensions) === false) {
            //Uh-oh not the correct extension so rolling back
            $pdo->rollback();
            die('message here...');
        } else {
            // file type is ok so proceeding
            // if the file already exists, get rid of it so we don't have 2 copies on the server
            if (file_exists($file_dir.$file_name)) {
               unlink($file_dir.$file_name);
            }
            // storing the attached file in designated directory
            move_uploaded_file($file_tmp, $file_dir.$file_name);
            // going to parse the file...
            $xml = simplexml_load_file('xml file to parse');
           // have tried to call $pdo->commit(): here to no avail.
            foreach ($xml->children() as $row) {
                foreach ($row as $obj) {
                    if (some checking things with the obj here yada yada yada) {
                        $insert_sql = "INSERT INTO another table(columns.....) //there is no AUTO_INCREMENT column attribute on any column in this table just FYI
                        VALUES(column values...)";
                        $stmt = $pdo->prepare($insert_sql);
                         // want the AI value here from the very first insert above but it's always zero (0)
                        $stmt->bindValue(':last_insert_id', intval($last_insert_id), PDO::PARAM_INT);
                        $stmt->bindValue(':some_column', strval($some_column));
                        $stmt->bindValue(':another_one', strval($another_one));
                        $stmt->execute(); 
                    }
                }
            }
            // all is good so committing the first insert
            $pdo->commit();
        }
    } else {
        // the file was not uploaded and it is not mandatory so committing the first insert here and the second insert never happens
        $pdo->commit();
    }

} catch (Exception $e) {
    if ($pdo->inTransaction()) {
        $pdo->rollback();
    } 
    throw $e;
    echo 'An error occurred.';
    echo 'Database Error '. $e->getMessage(). ' in '. $e->getFile().
    ': '. $e->getLine();   
}
}

我的目标是第一个插入总是被插入(应该没有失败)。第二个插入是可选的,具体取决于是否附加了文件。如果文件已附加并且所有文件操作都正常,那么我将在另一个表中插入一些值,并使用第二个表中第一个插入的 auto_increment 值(这个想法是作为外键)。

但无论出于何种原因,插入的值始终为零 (0)。

当代码成功执行时,两个表插入都完成(授予一个文件并且第二个插入甚至触发)...创建第一个表中的行,并创建第二个插入表中的 1 个或多个行,但它们有一个值在指定列中为 0,我希望它们包含第一次插入的 AI 值...

我试图调用$pdo->commit()其他几个对我来说“有意义”的地方,认为必须提交第一个插入才能使 AI 值甚至存在于该表上,但其中任何一个都没有运气......

我什至尝试了我在另一篇 Stackoverflow 帖子中看到的测试,以确保 PDO 没有做任何奇怪的事情,但 PDO 很好......

$conn = new PDO(connection info here);

$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());

以上确实返回:string(1) "1"

所以我认为 PDO 没问题(假设上述内容没有包含在事务中,我还没有尝试过)

希望我提供了足够清晰的细节......有谁知道为什么我得到 0 而不是最后一个插入 id?

非常感谢任何帮助,谢谢!

标签: phpmysqlpdomariadb

解决方案


您需要检查 $stmt->execute 的结果。阅读PDOStatement::execute上的文档,您会看到它返回一个布尔值:

成功时返回 TRUE,失败时返回 FALSE。

然后阅读PDOStatement::errorInfo上的文档。如果执行返回 FALSE,请检查此项。

$stmt->execute();

echo "\nPDOStatement::errorInfo():\n";
$arr = $stmt->errorInfo();
print_r($arr);

编辑:将错误输出到屏幕通常不是一个好主意,为了方便起见,我在这种情况下这样做了。更好的方法是编写一个日志文件:

$arr = $stmt->errorInfo();
file_put_contents("/path/to/file.log", print_r($arr, TRUE));


推荐阅读