yii 2.0与3.0事务核心逻辑一致但api差异显著:2.0需手动管理嵌套与保存点,isactive仅表php对象状态;3.0原生支持嵌套事务、自动保存点及连接健康检测,更安全清晰。

Yii 2.0 和 Yii 3.0 的数据库事务机制核心逻辑一致,但 API 设计、默认行为和封装程度有明显差异。关键不是“能不能用”,而是“怎么用才安全、清晰、不踩坑”。
Yii 2.0:手动管理为主,嵌套需自己兜底
2.0 的 beginTransaction() 不是真正嵌套——多次调用只是增加引用计数,共用同一个底层 PDO 事务。外层 rollback() 会一并干掉所有内层操作,不存在“局部回滚”。
- 标准写法推荐闭包式:
Yii::$app->db->transaction(function ($db) { /* 业务逻辑 */ });—— 自动 commit/rollback,异常即回滚,最简最稳 - 若需手动控制(比如跨多个方法协作),必须显式
$transaction = $db->beginTransaction(),再用try/catch包裹,commit()或rollback()必须成对出现 - 真要模拟嵌套(如子流程失败不影响主流程),得手动打保存点:
$transaction->getConnection()->createCommand('SAVEPOINT sp_name')->execute(),出错时执行ROLLBACK TO SAVEPOINT sp_name;MySQL/PostgreSQL 支持,SQLite 有限,SQL Server 语法不同 -
$transaction->isActive不代表数据库事务还活着,只表示这个 PHP 对象没被 commit/rollback 过——连接断开或超时后它仍可能返回true,不能靠它判断状态
Yii 3.0:更现代、更明确,事务对象可复用
3.0 基于 PHP 8+ 特性重构,事务 API 更语义化,支持原生嵌套(通过保存点自动管理),且默认启用严格错误模式。
- 基础用法类似:
$db->transaction(fn () => { /* 操作 */ });,但底层已自动处理 SAVEPOINT,子事务失败只回滚到对应保存点,不影响外层 - 手动方式更清晰:
$transaction = $db->beginTransaction();返回的是一个可 await 的TransactionInterface实例,支持链式调用如$transaction->isolationLevel(Transaction::ISOLATION_REPEATABLE_READ) - 嵌套事务无需手写 SQL:
$transaction->beginNested()直接创建保存点,$nested->rollback()仅回滚该段;外层commit()会级联提交所有成功子段 - 连接异常检测更强:事务对象自带健康检查,
$transaction->isActive()会真实探测连接状态,避免 2.0 中的“假活跃”问题
共通原则:别依赖框架自动兜底
无论 2.0 还是 3.0,事务安全不靠语法糖,而靠设计意识:
- 长事务慎用:避免在事务里做 HTTP 请求、文件读写、sleep 等阻塞操作,容易锁表或超时
- 读操作一般不进事务:除非需要一致性快照(如报表生成),否则
SELECT单独走连接更轻量 - 参数绑定必须做:用
createCommand($sql)->bindValue(':id', $id),绝不拼接 SQL 字符串 - 查数据别用
execute():它只返回影响行数,查要用queryAll()、queryOne()或scalar()











