Yii2.0.43中deleteAll()不自动启用事务,需手动开启beginTransaction()、commit()或rollBack();返回值为int,失败时返回false,条件数组需规范,大批量操作建议分页或改用createCommand()配合事务。

Yii2.0.43 中对 deleteAll() 加事务,核心是手动开启、提交或回滚,框架本身不会自动为批量删除包裹事务。
必须显式开启事务
Yii2 默认不为 deleteAll() 启用事务,哪怕你配置了全局连接级事务(如修改 Connection.php),也不推荐依赖这种侵入式改动。标准且安全的做法是业务层主动控制:
- 调用
Yii::$app->db->beginTransaction()获取事务对象 - 在
try块中执行deleteAll()及其他关联操作(比如连带删子表) - 成功则调用
$transaction->commit(),失败则$transaction->rollBack()
带事务的 deleteAll() 示例
假设你要按条件批量删除主表记录,并同步清理关联子表:
$transaction = Yii::$app->db->beginTransaction();
try {
$affected1 = Order::deleteAll(['status' => Order::STATUS_CANCELLED, 'created_at' => ['<', time() - 86400 * 30]]);
$affected2 = OrderItem::deleteAll(['order_id' => $affected1 > 0 ? (new Query())->select('id')->from('order')->where(['status' => Order::STATUS_CANCELLED]) : []]);
<pre class="brush:php;toolbar:false;">if ($affected1 === false || $affected2 === false) {
throw new Exception('批量删除失败');
}
$transaction->commit();} catch (\Exception $e) { $transaction->rollBack(); throw $e; }
注意事项
几个容易出错但很关键的点:
-
deleteAll() 返回受影响行数(int),不是布尔值:判断失败不能写
if (!$res),应写if ($res === false) -
条件数组格式必须规范:多条件必须用
['AND', [...], [...]]包裹,否则可能触发strtoupper() expects parameter 1 to be string错误 -
事务内不要混用原生 SQL 和 ActiveRecord:若同时用了
createCommand(),确保它也走同一个连接(Yii::$app->db),否则事务不生效 - 避免长事务:大批量删除建议分页执行(如每 1000 条一批),防止锁表时间过长
替代思路:用 Command + 事务更可控
如果条件特别复杂(含子查询、函数等),deleteAll() 不支持,可改用原生命令:
$transaction = Yii::$app->db->beginTransaction();
try {
$sql = 'DELETE FROM `order` WHERE status = :status AND created_at < :cutoff';
Yii::$app->db->createCommand($sql, [
':status' => Order::STATUS_CANCELLED,
':cutoff' => time() - 86400 * 30,
])->execute();
<pre class="brush:php;toolbar:false;">$transaction->commit();} catch (\Exception $e) { $transaction->rollBack(); throw $e; }
这种方式完全绕过 ActiveRecord 解析逻辑,条件自由度更高,也更容易与事务配合。


















