PHP事务开始语句主要用于确保数据库操作的原子性,通过mysqli_begin_transaction($link)或PDO的$pdo->beginTransaction()启动事务,事务执行过程中,多个SQL语句被视作单一单元,若中途失败可通过mysqli_rollback()或$pdo->rollBack()回滚,全部成功则用mysqli_commit()或$pdo->commit()提交,避免数据不一致,常用于涉及多表操作的场景,如转账、订单创建等,需配合错误处理机制确保数据安全。
PHP事务开始语句详解:从基础到实践
在数据库操作中,事务是保证数据一致性和完整性的核心机制,无论是金融转账、订单扣库存还是用户注册时的多表联动,都需要通过事务来确保一系列操作要么全部成功,要么全部失败,而在PHP中,事务的开始语句是控制这一流程的"起点",正确使用它对构建健壮的数据库应用至关重要,本文将从基础概念出发,结合PHP中主流数据库扩展(MySQLi/PDO)的用法,详细解析事务开始语句的使用方法、注意事项及最佳实践。
事务的核心概念:为什么需要事务?
在深入PHP事务开始语句之前,我们先明确事务(Transaction)的定义和核心特性,事务是数据库操作的最小执行单元,一组操作要么全部提交(Commit)生效,要么全部回滚(Rollback)撤销,不可分割,其核心特性可通过ACID原则(原子性Atomicity、一致性Consistency、隔离性Isolation、持久性Durability)概括:
- 原子性(Atomicity):事务内的操作不可分割,要么全部完成,要么全部不执行。
- 一致性(Consistency):事务执行前后,数据库状态必须一致(如转账总金额不变)。
- 隔离性(Isolation):并发事务之间互不干扰,一个事务的中间结果对其他事务不可见。
- 持久性(Durability):事务提交后,对数据库的修改永久保存,即使系统崩溃也不会丢失。
以电商下单场景为例,需要同时执行"扣减库存"、"创建订单"、"增加用户积分"三个操作,若其中一个失败(如库存不足),则所有操作需回滚,避免数据不一致,事务就是保证这一逻辑的关键,而事务的开始语句则是触发事务机制的"开关"。
PHP中的事务开始语句:MySQLi与PDO的写法
PHP操作数据库的主流扩展包括MySQLi(面向过程/面向对象)和PDO(PHP Data Objects,支持多种数据库),两者的事务开始语句略有不同,但核心逻辑一致:显式开启事务,关闭自动提交模式。
MySQLi中的事务开始语句
MySQLi提供了两种方式开启事务:
- 面向对象风格:
mysqli::begin_transaction()(PHP 5.6.0+ 推荐,语义更清晰) - 面向过程风格:
mysqli_autocommit($link, FALSE)(关闭自动提交,隐式开启事务)
示例:面向对象风格开启事务
$mysqli = new mysqli("localhost", "root", "password", "test_db");
if ($mysqli->connect_errno) {
die("连接失败: " . $mysqli->connect_error);
}
// 开启事务(推荐方式)
$mysqli->begin_transaction();
try {
// 执行SQL操作1:扣减库存
$result = $mysqli->query("UPDATE products SET stock = stock - 1 WHERE id = 1");
if (!$result) {
throw new Exception("库存更新失败");
}
// 执行SQL操作2:创建订单
$result = $mysqli->query("INSERT INTO orders (product_id, user_id, status) VALUES (1, 100, 'pending')");
if (!$result) {
throw new Exception("订单创建失败");
}
// 提交事务
$mysqli->commit();
echo "事务提交成功,操作完成!";
} catch (Exception $e) {
// 发生异常,回滚事务
$mysqli->rollback();
echo "事务回滚: " . $e->getMessage();
}
$mysqli->close();
示例:面向过程风格开启事务
$link = mysqli_connect("localhost", "root", "password", "test_db");
if (!$link) {
die("连接失败: " . mysqli_connect_error());
}
// 关闭自动提交(隐式开启事务)
mysqli_autocommit($link, FALSE);
try {
mysqli_query($link, "UPDATE products SET stock = stock - 1 WHERE id = 1");
mysqli_query($link, "INSERT INTO orders (product_id, user_id, status) VALUES (1, 100, 'pending')");
// 提交事务
mysqli_commit($link);
echo "事务提交成功!";
} catch (Exception $e) {
mysqli_rollback($link);
echo "事务回滚: " . $e->getMessage();
}
mysqli_close($link);
关键点:
begin_transaction()是PHP 5.6.0后引入的显式方法,比autocommit更直观,推荐使用。- 开启事务后,需手动调用
commit()提交或rollback()回滚。 - 在事务执行过程中,任何一条SQL语句失败都应触发异常并回滚。
- MySQLi默认的隔离级别是REPEATABLE READ,可通过
mysqli::query("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED");修改。
PDO中的事务开始语句
PDO提供了更简洁的事务控制方式,主要使用beginTransaction()方法:
try {
$pdo = new PDO("mysql:host=localhost;dbname=test_db", "root", "password");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 开启事务
$pdo->beginTransaction();
// 执行SQL操作1:扣减库存
$stmt = $pdo->prepare("UPDATE products SET stock = stock - 1 WHERE id = :id");
$stmt->execute(['id' => 1]);
// 执行SQL操作2:创建订单
$stmt = $pdo->prepare("INSERT INTO orders (product_id, user_id, status) VALUES (:product_id, :user_id, :status)");
$stmt->execute([
'product_id' => 1,
'user_id' => 100,
'status' => 'pending'
]);
// 提交事务
$pdo->commit();
echo "事务提交成功!";
} catch (Exception $e) {
// 发生异常,回滚事务
if (isset($pdo) && $pdo->inTransaction()) {
$pdo->rollback();
}
echo "事务回滚: " . $e->getMessage();
}
PDO事务特点:
- PDO支持多种数据库(MySQL、PostgreSQL、SQLite等),代码更具通用性。
- 使用预处理语句(prepare/execute)可以防止SQL注入,提高安全性。
inTransaction()方法可以检查当前是否处于事务中。- PDO默认的自动提交模式为开启,必须显式调用
beginTransaction()才能开启事务。
事务隔离级别与并发控制
事务的隔离级别决定了并发事务之间的相互影响程度,MySQL支持四种隔离级别:
**READ UNCOMMITTED