PHP MySQL 插入数据

Inserting one row with a prepared statement, reading the auto-increment ID, handling duplicate keys.

Beginner
Key PointsInsert with prepared statements; read the generated key via `lastInsertId()`.

Insert one row

PHP
<?php
$pdo = new PDO($dsn, $user, $pass, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);

$stmt = $pdo->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
$stmt->execute(["Tom", "tom@example.com"]);

echo "新增 ID: " . $pdo->lastInsertId() . "\n";
echo "影响行数: " . $stmt->rowCount() . "\n";
Output
新增 ID: 1
影响行数: 1

lastInsertId() must be called on the same connection right after the insert — it is connection state, not statement state.

Named placeholders

PHP
<?php
$stmt = $pdo->prepare(
    "INSERT INTO users (name, email, age) VALUES (:name, :email, :age)"
);

$stmt->execute([
    ":name"  => "Amy",
    ":email" => "amy@example.com",
    ":age"   => 25,
]);

echo "新增 ID: " . $pdo->lastInsertId() . "\n";
Output
新增 ID: 2

Named placeholders read better with many columns, and the same name may appear multiple times — positional ? cannot.

Duplicate key

PHP
<?php
$stmt = $pdo->prepare("INSERT INTO users (name, email) VALUES (?, ?)");

try {
    $stmt->execute(["Tom", "tom@example.com"]);
    echo "插入成功\n";
} catch (PDOException $e) {
    if ($e->getCode() === "23000") {
        echo "邮箱已存在,请换一个\n";
    } else {
        throw $e;
    }
}
Output
邮箱已存在,请换一个

23000 is the integrity-constraint SQLSTATE. To pinpoint which key, inspect $e->errorInfo[1]: 1062 is a duplicate entry.

Upsert

PHP
<?php
$sql = "INSERT INTO users (name, email, age) VALUES (?, ?, ?)
        ON DUPLICATE KEY UPDATE
            name = VALUES(name),
            age  = VALUES(age)";

$stmt = $pdo->prepare($sql);
$stmt->execute(["Tom", "tom@example.com", 30]);

echo "执行完毕\n";
echo "影响行数: " . $stmt->rowCount() . "\n";
Output
执行完毕
影响行数: 2
rowCount() is special here: 1 for insert, 2 for update, 0 when unchanged. Using it to detect insert-vs-update is error-prone.

Insert performance

PHP
<?php
// 慢:一行一个语句,1000 次网络往返
// 快:一条语句插多行,1 次往返
$rows = [
    ["Bob",  "bob@example.com",  28],
    ["Cara", "cara@example.com", 31],
    ["Dan",  "dan@example.com",  22],
];

$values = implode(",", array_fill(0, count($rows), "(?,?,?)"));
$flat   = array_merge(...$rows);

$stmt = $pdo->prepare("INSERT INTO users (name, email, age) VALUES $values");
$stmt->execute($flat);

echo "插入行数: " . $stmt->rowCount() . "\n";
Output
插入行数: 3

array_merge(...$rows) flattens the 2D array to match the ordered placeholders — the standard bulk-insert idiom.

Huge batches hit max_allowed_packet. Batch 500–1000 rows per statement.

Friends & Partners