
当多个 insert 操作需满足“全成功或全失败”时,必须结合 try/catch 捕获异常,并在出错时显式调用 rollback();仅调用 begin_transaction() 和 commit() 无法自动回滚失败语句。
MySQLi 的事务机制本身不会自动感知 SQL 语法错误或约束冲突——mysqli_query() 遇到非法语句(如 IINSERT)时默认返回 false,但不会抛出异常,除非你启用异常模式。因此,原代码中即使第二条 SQL 因拼写错误执行失败,commit() 仍会被无条件调用,导致第一条合法插入被永久提交,违背原子性要求。
✅ 正确做法是:启用 MySQLi 异常模式 + try/catch + 显式 rollback。需在连接后设置 mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT),使所有错误触发 mysqli_sql_exception:
begin_transaction();
// 这条会成功
mysqli_query($connection, "INSERT INTO categories (name) VALUES ('Electronics')");
// 这条因表名/语法错误触发异常(如 IINSERT → INSERT 拼错)
mysqli_query($connection, "IINSERT INTO categories (name) VALUES ('Books')");
// 仅当全部成功才提交
$connection->commit();
echo "✅ 所有插入成功完成。";
} catch (mysqli_sql_exception $e) {
// 任一语句失败即回滚整个事务
$connection->rollback();
echo "❌ 事务已回滚。错误:" . $e->getMessage();
}
?>⚠️ 注意事项:
- 必须调用 mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT),否则 mysqli_query() 失败仅返回 false,不会进入 catch 块;
- rollback() 必须在 catch 中显式调用,PHP 不会自动回滚;
- 事务仅对支持事务的存储引擎(如 InnoDB)生效,MyISAM 不支持;
- 避免在事务中执行非数据库操作(如文件写入、HTTP 请求),因其无法回滚。
? 总结:事务的原子性不是自动保障的,而是依赖开发者主动检查执行结果并协调 commit()/rollback()。启用严格异常模式 + 结构化异常处理,是确保数据一致性的关键实践。










