ZetCode

PHP PDO::inTransaction 方法

最后修改于 2025 年 4 月 19 日

PDO::inTransaction 方法检查当前是否有一个活动的事务。如果事务正在进行,它返回 true,否则返回 false。

基本定义

PDO::inTransaction 是 PHP 中 PDO 类的一个方法。它用于确定数据库连接是否处于事务处理过程中。

语法:public PDO::inTransaction(): bool。无需参数。返回一个布尔值,指示事务状态。

基本的 inTransaction 检查

此示例显示了 PDO::inTransaction 方法的基本用法。

in_transaction_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);
    
    echo "Before transaction: " . ($pdo->inTransaction() ? 'Yes' : 'No') . "\n";
    
    $pdo->beginTransaction();
    echo "During transaction: " . ($pdo->inTransaction() ? 'Yes' : 'No') . "\n";
    
    $pdo->commit();
    echo "After transaction: " . ($pdo->inTransaction() ? 'Yes' : 'No') . "\n";
} catch (PDOException $e) {
    echo "Error: " . $e->getMessage();
}

此代码在事务之前、期间和之后检查事务状态。输出显示之前为 false,期间为 true,事务后为 false。

嵌套事务检查

这演示了 inTransaction 在嵌套事务中的行为。

in_transaction_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);
    
    echo "Level 0: " . ($pdo->inTransaction() ? 'Yes' : 'No') . "\n";
    
    $pdo->beginTransaction();
    echo "Level 1: " . ($pdo->inTransaction() ? 'Yes' : 'No') . "\n";
    
    $pdo->beginTransaction(); // This will throw an exception
    echo "Level 2: " . ($pdo->inTransaction() ? 'Yes' : 'No') . "\n";
    
    $pdo->commit();
} catch (PDOException $e) {
    echo "Error: " . $e->getMessage() . "\n";
    echo "Current status: " . ($pdo->inTransaction() ? 'Yes' : 'No') . "\n";
}

这表明 PDO 不支持真正的嵌套事务。第二次 beginTransaction 会抛出异常。inTransaction 仍然返回 true。

带回滚的 inTransaction

此示例显示了回滚操作期间的事务状态。

in_transaction_rollback.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();
    echo "After begin: " . ($pdo->inTransaction() ? 'Yes' : 'No') . "\n";
    
    $pdo->exec("INSERT INTO test (name) VALUES ('Test')");
    
    $pdo->rollBack();
    echo "After rollback: " . ($pdo->inTransaction() ? 'Yes' : 'No') . "\n";
} catch (PDOException $e) {
    echo "Error: " . $e->getMessage();
}

代码启动一个事务,执行插入,然后回滚。inTransaction 在回滚之前返回 true,在完成之后返回 false。

inTransaction 在错误处理中的应用

这显示了如何在错误处理场景中使用 inTransaction。

in_transaction_error.php
<?php

declare(strict_types=1);

$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

try {
    $pdo->beginTransaction();
    
    $pdo->exec("UPDATE accounts SET balance = balance - 100 WHERE user_id = 1");
    $pdo->exec("INVALID SQL STATEMENT"); // This will fail
    
    $pdo->commit();
} catch (PDOException $e) {
    echo "Error occurred: " . $e->getMessage() . "\n";
    echo "Still in transaction: " . ($pdo->inTransaction() ? 'Yes' : 'No') . "\n";
    
    if ($pdo->inTransaction()) {
        $pdo->rollBack();
        echo "Transaction rolled back\n";
    }
}

当发生错误时,inTransaction 有助于确定是否需要回滚。这可以防止在没有活动事务时尝试回滚。

带保存点的 inTransaction

这演示了在使用保存点时的事务状态。

in_transaction_savepoint.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();
    echo "Main transaction: " . ($pdo->inTransaction() ? 'Yes' : 'No') . "\n";
    
    $pdo->exec("SAVEPOINT point1");
    echo "After savepoint: " . ($pdo->inTransaction() ? 'Yes' : 'No') . "\n";
    
    $pdo->exec("ROLLBACK TO SAVEPOINT point1");
    echo "After rollback to savepoint: " . ($pdo->inTransaction() ? 'Yes' : 'No') . "\n";
    
    $pdo->commit();
} catch (PDOException $e) {
    echo "Error: " . $e->getMessage();
}

保存点不影响整体事务状态。在提交或回滚之前,inTransaction 在整个操作过程中始终返回 true。

不同数据库的 inTransaction

这表明 inTransaction 如何与不同的数据库驱动程序一起工作。

in_transaction_drivers.php
<?php

declare(strict_types=1);

// MySQL example
try {
    $mysql = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
    $mysql->beginTransaction();
    echo "MySQL inTransaction: " . ($mysql->inTransaction() ? 'Yes' : 'No') . "\n";
    $mysql->commit();
} catch (PDOException $e) {
    echo "MySQL Error: " . $e->getMessage();
}

// SQLite example
try {
    $sqlite = new PDO('sqlite:test.db');
    $sqlite->beginTransaction();
    echo "SQLite inTransaction: " . ($sqlite->inTransaction() ? 'Yes' : 'No') . "\n";
    $sqlite->commit();
} catch (PDOException $e) {
    echo "SQLite Error: " . $e->getMessage();
}

inTransaction 方法在不同的数据库驱动程序中行为一致。MySQL 和 SQLite 都显示相同的行为。

实际事务管理

这展示了在数据库操作中 inTransaction 的实际用途。

in_transaction_practical.php
<?php

declare(strict_types=1);

function transferFunds(PDO $pdo, int $from, int $to, float $amount): bool {
    if ($pdo->inTransaction()) {
        throw new RuntimeException("Already in transaction");
    }
    
    try {
        $pdo->beginTransaction();
        
        // Check sender balance
        $stmt = $pdo->prepare("SELECT balance FROM accounts WHERE id = ?");
        $stmt->execute([$from]);
        $balance = $stmt->fetchColumn();
        
        if ($balance < $amount) {
            throw new RuntimeException("Insufficient funds");
        }
        
        // Perform transfer
        $pdo->prepare("UPDATE accounts SET balance = balance - ? WHERE id = ?")
            ->execute([$amount, $from]);
        $pdo->prepare("UPDATE accounts SET balance = balance + ? WHERE id = ?")
            ->execute([$amount, $to]);
            
        $pdo->commit();
        return true;
    } catch (Exception $e) {
        if ($pdo->inTransaction()) {
            $pdo->rollBack();
        }
        error_log("Transfer failed: " . $e->getMessage());
        return false;
    }
}

// Usage
try {
    $pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    $success = transferFunds($pdo, 1, 2, 100.00);
    echo "Transfer " . ($success ? "succeeded" : "failed") . "\n";
} catch (PDOException $e) {
    echo "Database error: " . $e->getMessage();
}

这个实际示例使用 inTransaction 在开始新事务之前检查是否存在现有事务。它还在回滚之前验证事务状态。

最佳实践

来源

PHP PDO::inTransaction 文档

本教程介绍了 PDO::inTransaction 方法,并提供了实际示例,展示了其在不同场景下的用法。

作者

我的名字是 Jan Bodnar,我是一位充满激情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。至今,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出 所有 PHP PDO 函数