如何使用交易来确保PHP中的数据一致性?
                           
天天向上
发布: 2025-06-28 12:56:13

原创
422 人浏览过

在 PHP 中,为了确保数据一致性(尤其在多步写入数据库的操作中),我们使用 数据库事务(transaction)。事务可以保证要么全部成功,要么全部失败,防止因部分执行成功而导致数据异常。


一、什么是事务(Transaction)

事务是一组 SQL 操作的集合,这些操作要么全部执行,要么一个也不执行。事务具有四大特性,简称 ACID

特性含义
原子性(Atomicity)操作不可分割,全部成功或全部失败
一致性(Consistency)执行前后数据满足一致性规则
隔离性(Isolation)多个事务之间互不干扰
持久性(Durability)提交后结果永久保存

二、在 PHP 中使用事务的前提条件

必须使用支持事务的数据库引擎,如 MySQL 的 InnoDB(❌ MyISAM 不支持事务)。


三、使用 PDO 执行事务(推荐)

示例:转账操作(A → B)

<?php
$pdo = new PDO("mysql:host=localhost;dbname=test", "root", "");

// 设置为抛出异常
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

try {
    // 开启事务
    $pdo->beginTransaction();

    // 用户 A 扣款
    $stmt1 = $pdo->prepare("UPDATE users SET balance = balance - :amount WHERE id = :from");
    $stmt1->execute([':amount' => 100, ':from' => 1]);

    // 用户 B 加款
    $stmt2 = $pdo->prepare("UPDATE users SET balance = balance + :amount WHERE id = :to");
    $stmt2->execute([':amount' => 100, ':to' => 2]);

    // 提交事务
    $pdo->commit();
    echo "转账成功!";

} catch (Exception $e) {
    // 回滚事务
    $pdo->rollBack();
    echo "转账失败:" . $e->getMessage();
}

一旦任意 SQL 报错(比如余额不足或语法错误),事务会回滚,保证不会发生“扣了 A 没加到 B”的数据错乱。


四、事务失效的常见原因

原因描述
使用了 MyISAM 表不支持事务,需改为 InnoDB
没启用异常处理PDO 默认不抛异常,需手动设置 ERRMODE_EXCEPTION
部分语句不在事务中比如某些写操作在事务开始之外
写操作自动提交如 autocommit 没关闭或写在非事务内

五、使用 mysqli 事务(较低级)

$conn = new mysqli("localhost", "root", "", "test");
$conn->autocommit(false); // 关闭自动提交

try {
    $conn->query("UPDATE users SET balance = balance - 100 WHERE id = 1");
    $conn->query("UPDATE users SET balance = balance + 100 WHERE id = 2");

    $conn->commit();
    echo "转账成功";
} catch (Exception $e) {
    $conn->rollback();
    echo "转账失败:" . $e->getMessage();
}

六、实战建议

场景是否建议用事务
用户注册(多表)✅ 是
用户发帖(帖子 + 附件)✅ 是
电商下单(订单、库存、支付)✅ 必须
仅查询操作❌ 不建议(无意义)

七、安全与性能提示

  • 尽量控制事务时间(避免事务期间长时间等待用户输入)
  • 避免在事务中执行过多非必要逻辑
  • 使用死锁处理逻辑(如捕获后重试)

📚 八、权威参考资料


总结:事务使用流程(PDO)

try {
    $pdo->beginTransaction();

    // 写操作 1
    // 写操作 2

    $pdo->commit();  // 一起成功
} catch (Exception $e) {
    $pdo->rollBack();  // 任一失败,全体失败
}

更多详细内容,请关注其他相关文章!

发表回复 0

Your email address will not be published. Required fields are marked *