PHP数据回滚怎么操作

wen PHP项目 24

本文目录导读:

PHP数据回滚怎么操作

  1. 使用 PDO(PHP Data Objects)进行回滚
  2. 使用 MySQLi(MySQL Improved)进行回滚
  3. 使用 Laravel(Eloquent ORM)进行回滚
  4. 必须注意的关键点(避免常见错误)
  5. 完整示例:带日志和回滚的银行转账
  6. 总结操作流程

在PHP中实现数据回滚,主要依赖于数据库事务(Transaction),核心思路是:将多个数据库操作(增、删、改)组合成一个原子操作,要么全部成功(Commit),要么全部失败(Rollback)。

以下是三种主流方式的操作详解:

使用 PDO(PHP Data Objects)进行回滚

这是最推荐的方式,支持多种数据库(MySQL、PostgreSQL等)。

<?php
try {
    // 1. 创建 PDO 连接(务必关闭自动提交)
    $pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8mb4', 'root', 'password');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    // 2. 关闭自动提交,开始事务
    $pdo->beginTransaction();
    // 3. 执行多个数据操作
    // 操作1: 更新用户余额
    $sql1 = "UPDATE users SET balance = balance - 100 WHERE id = 1";
    $pdo->exec($sql1);
    // 操作2: 插入订单记录
    $sql2 = "INSERT INTO orders (user_id, amount, status) VALUES (1, 100, 'pending')";
    $pdo->exec($sql2);
    // 操作3: 检查用户余额是否足够(模拟业务逻辑检查)
    $stmt = $pdo->query("SELECT balance FROM users WHERE id = 1");
    $user = $stmt->fetch();
    if ($user['balance'] < 0) {
        // 余额不足,抛出异常触发回滚
        throw new Exception("余额不足,需要回滚!");
    }
    // 4. 全部成功,提交事务
    $pdo->commit();
    echo "操作成功完成!";
} catch (Exception $e) {
    // 5. 发生任何异常,回滚事务
    $pdo->rollBack();
    echo "操作失败,已回滚:" . $e->getMessage();
}
?>

关键点

  • PDO::ATTR_ERRMODE 设为异常模式,方便捕获错误。
  • beginTransaction() 自动关闭自动提交。
  • rollBack() 撤销 beginTransaction 之后的所有操作。

使用 MySQLi(MySQL Improved)进行回滚

适用于项目已使用 MySQLi 扩展的情况。

<?php
$mysqli = new mysqli("localhost", "root", "password", "test");
// 检查连接
if ($mysqli->connect_error) {
    die("连接失败: " . $mysqli->connect_error);
}
// 设置自动提交为 false
$mysqli->autocommit(FALSE);
try {
    // 操作1: 扣钱
    $result1 = $mysqli->query("UPDATE users SET balance = balance - 100 WHERE id = 1");
    if (!$result1) throw new Exception("扣钱失败");
    // 操作2: 加钱到另一个账户
    $result2 = $mysqli->query("UPDATE users SET balance = balance + 100 WHERE id = 2");
    if (!$result2) throw new Exception("加钱失败");
    // 全部成功 → 提交
    $mysqli->commit();
    echo "转账成功";
} catch (Exception $e) {
    // 失败 → 回滚
    $mysqli->rollback();
    echo "转账失败,已回滚:" . $e->getMessage();
}
$mysqli->close();
?>

注意:MySQLi 的 autocommit(FALSE)commit() / rollback() 手动控制事务。


使用 Laravel(Eloquent ORM)进行回滚

如果你使用 Laravel 框架,有更简洁的语法:

use Illuminate\Support\Facades\DB;
try {
    DB::beginTransaction();
    // 业务操作
    $user = User::find(1);
    $user->balance -= 100;
    $user->save();
    Order::create([
        'user_id' => 1,
        'amount' => 100
    ]);
    // 手动检查并抛异常
    if ($user->balance < 0) {
        throw new \Exception("余额不足");
    }
    DB::commit();
    return "操作成功";
} catch (\Exception $e) {
    DB::rollBack();
    return "操作失败,已回滚:" . $e->getMessage();
}

必须注意的关键点(避免常见错误)

问题 正确做法
引擎必须是 InnoDB MyISAM 引擎不支持事务,操作不会回滚,检查表引擎:SHOW TABLE STATUS LIKE 'your_table'
捕获所有异常 要捕获 ExceptionThrowable,不能只捕获特定错误,否则未捕获的错误会跳过 rollback
不要在事务中使用 die()exit() 会导致连接断开,事务自动回滚但可能不完整
不要在事务内部混合多层 try-catch 确保一个事务对应一个 try-catch 块,否则可能误提交或重复回滚
注意嵌套事务 PHP 原生 PDO 不原生支持嵌套事务(MySQL 也不支持),Laravel 等框架会模拟,但建议避免复杂的嵌套

完整示例:带日志和回滚的银行转账

<?php
function transferMoney($fromId, $toId, $amount) {
    $pdo = new PDO('mysql:host=localhost;dbname=bank', 'root', 'password');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    try {
        $pdo->beginTransaction();
        // 扣款
        $stmt = $pdo->prepare("UPDATE accounts SET balance = balance - ? WHERE id = ? AND balance >= ?");
        $stmt->execute([$amount, $fromId, $amount]);
        if ($stmt->rowCount() === 0) {
            throw new Exception("扣款失败(余额不足或账户不存在)");
        }
        // 入账
        $stmt = $pdo->prepare("UPDATE accounts SET balance = balance + ? WHERE id = ?");
        $stmt->execute([$amount, $toId]);
        if ($stmt->rowCount() === 0) {
            throw new Exception("入账失败(收款账户不存在)");
        }
        // 记录日志
        $pdo->exec("INSERT INTO transfer_log (from_id, to_id, amount, time) VALUES ($fromId, $toId, $amount, NOW())");
        $pdo->commit();
        return "转账成功";
    } catch (Exception $e) {
        $pdo->rollBack();
        error_log("转账失败: " . $e->getMessage());
        return "转账失败,交易已撤销";
    }
}

总结操作流程

  1. 关闭自动提交 / 开始事务
  2. 执行所有业务操作
  3. 进行业务规则校验(余额检查、唯一性检查等)
  4. 全部成功 → 提交
  5. 任一失败 → 回滚

这就是 PHP 中实现数据回滚的核心方式,如果你使用的是特定框架(ThinkPHP、Symfony 等),通常都有类似 Db::transaction() 的便捷方法,原理相同。

抱歉,评论功能暂时关闭!