无尘阁日记

无尘阁日记

yii2更新后我要重新获取ReportsProjects::updateAll($attributes, ['UUID' => $isCurrentReport->UUID]);或者刷新这个model
2026-03-03

这个问题本质是:

updateAll() 是直接走 SQL,不会更新当前内存里的 model 实例。

所以你现在手里 $isCurrentReport 还是旧数据。

一、为什么会这样?

ReportsProjects::updateAll($attributes, ['UUID' => $uuid]);

这句是:

  • 直接执行 UPDATE SQL

  • 不触发 beforeSave / afterSave

  • 不更新当前对象属性

  • 不刷新 ActiveRecord 缓存

所以 $isCurrentReport 还是旧值。

二、正确做法(推荐三种)

✅ 方案一:刷新当前 model(最干净)

$isCurrentReport->refresh();

refresh() 会:

  • 根据主键重新查询数据库

  • 用最新数据覆盖当前对象

⚠ 前提:当前 model 必须有主键值。

✅ 方案二:重新查询(更保险)

$isCurrentReport = ReportsProjects::find()
    ->where(['UUID' => $isCurrentReport->UUID])
    ->one();

适合:

  • 你担心主键不是默认 id

  • UUID 是唯一键但不是主键

✅ 方案三:别用 updateAll,直接用 save(推荐做法)

如果你已经有 $isCurrentReport

$isCurrentReport->attributes = $attributes;
$isCurrentReport->save(false);

优点:

  • 自动更新内存数据

  • 触发 AR 事件

  • 不需要 refresh

除非你批量更新,否则尽量不用 updateAll()

三、批量更新后怎么刷新多个?

如果你 updateAll 更新了多条数据:

ReportsProjects::updateAll($attributes, $condition);

那就只能重新查:

$list = ReportsProjects::find()
    ->where($condition)
    ->all();

四、为什么很多人踩坑?

因为 updateAll:

  • 不走 AR 层

  • 不触发行为(behavior)

  • 不更新时间戳(除非你自己传)

  • 不触发 optimistic lock

它是“纯 SQL 快速通道”。

五、最安全建议(架构级建议)

如果不是极限性能场景:

✔ 用 $model->save()
✔ 少用 updateAll()
✔ 批量场景再用 updateAll

六、给你一个最佳实践写法(企业级)

$transaction = Yii::$app->db->beginTransaction();
try {

    ReportsProjects::updateAll($attributes, ['UUID' => $uuid]);

    $model = ReportsProjects::findOne(['UUID' => $uuid]);

    $transaction->commit();

} catch (\Throwable $e) {

    $transaction->rollBack();
    throw $e;
}

这样:

  • 数据一致

  • 状态最新

  • 可控异常

如果你告诉我:

  • UUID 是不是主键?

  • 你是单条更新还是批量?

  • 有没有乐观锁字段?

我可以给你一版“更严谨的生产级写法”。