ZetCode

PHP PDO::lastInsertId 方法

最后修改于 2025 年 4 月 19 日

PDO::lastInsertId 方法用于检索最后插入行的ID。它通常在对具有自动增量列的 INSERT 操作之后使用。

基本定义

PDO::lastInsertId 返回最后一次 INSERT 查询生成的ID。它适用于 MySQL、SQLite、PostgreSQL 等数据库的自动增量列。

语法:public PDO::lastInsertId(?string $name = null): string|false。对于大多数数据库,可以省略 $name 参数。失败时返回 false。

lastInsertId 基本示例

这展示了在 INSERT 操作后 lastInsertId 的最简单用法。

pdo_lastinsertid_basic.php
<?php

declare(strict_types=1);

try {
    $pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    $stmt = $pdo->prepare('INSERT INTO users (name, email) VALUES (?, ?)');
    $stmt->execute(['Jane Smith', 'jane@example.com']);
    
    $lastId = $pdo->lastInsertId();
    echo "Last inserted ID: " . $lastId;
} catch (PDOException $e) {
    echo "Error: " . $e->getMessage();
}

这会插入一个新用户并检索自动生成的ID。ID来自 users 表中的 auto-increment 列。请始终检查错误。

lastInsertId 的多表操作

在处理多个表时,lastInsertId 会获取最新的ID。

pdo_lastinsertid_multiple.php
<?php

declare(strict_types=1);

try {
    $pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    // Insert into first table
    $pdo->exec("INSERT INTO products (name, price) VALUES ('Laptop', 999.99)");
    $productId = $pdo->lastInsertId();
    
    // Insert into second table
    $pdo->exec("INSERT INTO orders (product_id, quantity) VALUES ($productId, 1)");
    $orderId = $pdo->lastInsertId();
    
    echo "Product ID: $productId, Order ID: $orderId";
} catch (PDOException $e) {
    echo "Error: " . $e->getMessage();
}

这展示了向两个表插入数据并获取两个ID。每次 INSERT 操作都会更新 lastInsertId 的值。这些ID用于链接记录。

lastInsertId 与事务

lastInsertId 在事务内工作,在提交前返回ID。

pdo_lastinsertid_transaction.php
<?php

declare(strict_types=1);

try {
    $pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    $pdo->beginTransaction();
    
    $stmt = $pdo->prepare('INSERT INTO logs (message) VALUES (?)');
    $stmt->execute(['System started']);
    $logId = $pdo->lastInsertId();
    
    $pdo->commit();
    
    echo "Log entry created with ID: $logId";
} catch (PDOException $e) {
    $pdo->rollBack();
    echo "Error: " . $e->getMessage();
}

这演示了事务中的 lastInsertId。ID在提交前可用。如果事务失败,ID将无效。

lastInsertId 与 SQLite

SQLite 处理 lastInsertId 的方式与 MySQL 略有不同。

pdo_lastinsertid_sqlite.php
<?php

declare(strict_types=1);

try {
    $pdo = new PDO('sqlite:test.db');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    $pdo->exec('CREATE TABLE IF NOT EXISTS items (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)');
    
    $stmt = $pdo->prepare('INSERT INTO items (name) VALUES (?)');
    $stmt->execute(['Sample Item']);
    
    $lastId = $pdo->lastInsertId();
    echo "SQLite last inserted ID: " . $lastId;
} catch (PDOException $e) {
    echo "Error: " . $e->getMessage();
}

SQLite 需要 AUTOINCREMENT 来实现自增列。lastInsertId 返回 ROWID,它对于 SQLite 表始终可用。

lastInsertId 与 PostgreSQL

PostgreSQL 需要序列名称才能使 lastInsertId 正常工作。

pdo_lastinsertid_postgresql.php
<?php

declare(strict_types=1);

try {
    $pdo = new PDO('pgsql:host=localhost;dbname=testdb', 'user', 'password');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    $stmt = $pdo->prepare('INSERT INTO customers (name) VALUES (?)');
    $stmt->execute(['Acme Corp']);
    
    // PostgreSQL requires sequence name
    $lastId = $pdo->lastInsertId('customers_id_seq');
    echo "PostgreSQL last inserted ID: " . $lastId;
} catch (PDOException $e) {
    echo "Error: " . $e->getMessage();
}

PostgreSQL 使用序列来实现自增。序列名称遵循 pattern tablename_columnname_seq。必须将其传递给 lastInsertId。

处理 lastInsertId 错误

lastInsertId 可能会失败并返回 false,这应该被处理。

pdo_lastinsertid_error.php
<?php

declare(strict_types=1);

try {
    $pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    // Table without auto-increment
    $pdo->exec('CREATE TEMPORARY TABLE temp_data (id INT, value TEXT)');
    $pdo->exec("INSERT INTO temp_data VALUES (1, 'Test')");
    
    $lastId = $pdo->lastInsertId();
    if ($lastId === false) {
        echo "No auto-increment value available";
    } else {
        echo "Last ID: $lastId";
    }
} catch (PDOException $e) {
    echo "Error: " . $e->getMessage();
}

这展示了如何处理 lastInsertId 失败的情况。如果没有自增列,它将返回 false。请始终检查返回值以处理错误。

lastInsertId 与多连接

每个 PDO 连接都维护自己的 lastInsertId 值。

pdo_lastinsertid_multiconn.php
<?php

declare(strict_types=1);

try {
    // First connection
    $pdo1 = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
    $pdo1->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    // Second connection
    $pdo2 = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
    $pdo2->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    $pdo1->exec("INSERT INTO users (name) VALUES ('Connection 1 User')");
    $id1 = $pdo1->lastInsertId();
    
    $pdo2->exec("INSERT INTO users (name) VALUES ('Connection 2 User')");
    $id2 = $pdo2->lastInsertId();
    
    echo "Connection 1 ID: $id1, Connection 2 ID: $id2";
} catch (PDOException $e) {
    echo "Error: " . $e->getMessage();
}

这表明每个 PDO 实例都跟踪自己的 lastInsertId。一个连接上的操作不会影响另一个连接的 lastInsertId。

最佳实践

来源

PHP PDO::lastInsertId 文档

本教程涵盖了 PDO::lastInsertId 方法,并提供了实际示例,展示了其在不同数据库系统和场景中的用法。

作者

我叫 Jan Bodnar,我是一位充满激情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。至今,我已撰写了超过 1,400 篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出 所有 PHP PDO 函数