ZetCode

PHP PDO::commit 方法

最后修改于 2025 年 4 月 19 日

PHP 中的 PDO::commit 方法用于最终确定一个事务,使所有更改在数据库中永久生效。它与 PDO 的事务功能一起使用。

基本定义

PDO::commit 提交当前事务。它使得自事务开始以来所做的所有更改永久生效。该方法在成功时返回 true。

语法:public PDO::commit(): bool。如果当前没有活动事务或提交失败,它将抛出 PDOException。

简单的事务提交示例

这展示了一个基本的事务提交。

pdo_commit_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);
    
    $pdo->beginTransaction();
    $pdo->exec("INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com')");
    $pdo->commit();
    
    echo "Transaction committed successfully";
} catch (PDOException $e) {
    $pdo->rollBack();
    echo "Error: " . $e->getMessage();
}

这会启动一个事务,插入一条记录,然后提交它。如果发生任何错误,事务将被回滚。提交操作会使插入永久生效。

事务中的多个操作

这演示了将多个操作作为一个事务进行提交。

pdo_commit_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);
    
    $pdo->beginTransaction();
    
    $pdo->exec("UPDATE products SET stock = stock - 5 WHERE id = 101");
    $pdo->exec("INSERT INTO orders (product_id, quantity) VALUES (101, 5)");
    
    $pdo->commit();
    echo "Order processed successfully";
} catch (PDOException $e) {
    $pdo->rollBack();
    echo "Order failed: " . $e->getMessage();
}

这在一个事务中更新产品库存并创建一个订单。这两个操作一起成功或一起失败。提交操作会应用这两个更改。

使用预处理语句提交

这展示了使用预处理语句提交事务。

pdo_commit_prepared.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, created_at) VALUES (?, NOW())");
    $stmt->execute(['System started']);
    $stmt->execute(['User logged in']);
    
    $pdo->commit();
    echo "Log entries committed";
} catch (PDOException $e) {
    $pdo->rollBack();
    echo "Logging failed: " . $e->getMessage();
}

这使用预处理语句在事务中插入多个日志条目。提交确保所有插入一起保存。预处理语句更安全。

条件提交

这演示了仅在满足特定条件时才提交。

pdo_commit_conditional.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("UPDATE accounts SET balance = balance - ? WHERE id = ?");
    $stmt->execute([100, 1]);
    
    $balance = $pdo->query("SELECT balance FROM accounts WHERE id = 1")->fetchColumn();
    
    if ($balance >= 0) {
        $pdo->commit();
        echo "Transaction committed";
    } else {
        $pdo->rollBack();
        echo "Insufficient funds - transaction rolled back";
    }
} catch (PDOException $e) {
    $pdo->rollBack();
    echo "Error: " . $e->getMessage();
}

这会在提交前检查账户余额。只有当余额保持为正时,事务才会提交。否则,它将回滚更改。

带提交的嵌套事务

这展示了 PDO 如何处理嵌套事务(模拟的)。

pdo_commit_nested.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(); // Outer transaction
    
    $pdo->exec("INSERT INTO events (name) VALUES ('Process started')");
    
    try {
        $pdo->beginTransaction(); // Inner transaction
        $pdo->exec("UPDATE counters SET value = value + 1 WHERE name = 'events'");
        $pdo->commit(); // Commits inner transaction
    } catch (Exception $e) {
        $pdo->rollBack(); // Rolls back inner transaction
        throw $e;
    }
    
    $pdo->commit(); // Commits outer transaction
    echo "All transactions committed";
} catch (PDOException $e) {
    $pdo->rollBack(); // Rolls back outer transaction
    echo "Error: " . $e->getMessage();
}

PDO 不支持真正的嵌套事务,但会模拟它们。每次提交都对应于其 `beginTransaction`。外部提交使所有更改永久生效。

带错误处理的提交

这演示了提交操作周围的正确错误处理。

pdo_commit_error_handling.php
<?php

declare(strict_types=1);

$pdo = null;

try {
    $pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    $pdo->beginTransaction();
    $pdo->exec("DELETE FROM temp_data WHERE created_at < DATE_SUB(NOW(), INTERVAL 1 DAY)");
    
    if (!$pdo->commit()) {
        throw new Exception("Commit failed");
    }
    
    echo "Old data cleaned successfully";
} catch (PDOException $e) {
    if ($pdo && $pdo->inTransaction()) {
        $pdo->rollBack();
    }
    echo "Database error: " . $e->getMessage();
} catch (Exception $e) {
    if ($pdo && $pdo->inTransaction()) {
        $pdo->rollBack();
    }
    echo "Error: " . $e->getMessage();
}

这展示了围绕提交的健壮错误处理。它会检查提交的返回值,并确保在所有错误情况下都进行回滚。`inTransaction` 检查可防止错误。

数据库类中的提交

这演示了在数据库包装器类中使用 `commit`。

pdo_commit_class.php
<?php

declare(strict_types=1);

class Database {
    private PDO $pdo;
    
    public function __construct(string $dsn, string $user, string $pass) {
        $this->pdo = new PDO($dsn, $user, $pass);
        $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    }
    
    public function transferFunds(int $from, int $to, float $amount): bool {
        try {
            $this->pdo->beginTransaction();
            
            $stmt = $this->pdo->prepare("UPDATE accounts SET balance = balance - ? WHERE id = ?");
            $stmt->execute([$amount, $from]);
            
            $stmt = $this->pdo->prepare("UPDATE accounts SET balance = balance + ? WHERE id = ?");
            $stmt->execute([$amount, $to]);
            
            $this->pdo->commit();
            return true;
        } catch (PDOException $e) {
            $this->pdo->rollBack();
            return false;
        }
    }
}

$db = new Database('mysql:host=localhost;dbname=testdb', 'user', 'password');
if ($db->transferFunds(1, 2, 50.00)) {
    echo "Funds transferred successfully";
} else {
    echo "Transfer failed";
}

这将在类方法中封装事务处理。只有在两个更新都成功时才提交。该方法返回一个布尔值表示成功。

最佳实践

来源

PHP PDO::commit 文档

本教程介绍了 PDO::commit 方法,并通过实际示例展示了不同场景下的事务处理。

作者

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

列出 所有 PHP PDO 函数