Yii 默认不自动更新 updated_at,需显式配置 TimestampBehavior:在 behaviors() 中指定 EVENT_BEFORE_INSERT 和 EVENT_BEFORE_UPDATE 的字段映射,并根据字段类型选择 time() 或 NOW() 作为 value 值。

updated_at 不更新,不是 Yii 没干活,而是你没告诉它“什么时候该更新”——ActiveRecord 默认不会自动维护时间戳字段,必须显式配置行为(Behavior)。
确保 TimestampBehavior 正确配置
这是最常见、也最易忽略的一环。Yii 的 AR 不像 Laravel 那样默认处理 created_at/updated_at,必须手动挂载 TimestampBehavior:
public function behaviors()
{
return [
'timestamp' => [
'class' => \yii\behaviors\TimestampBehavior::class,
'attributes' => [
\yii\db\ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
\yii\db\ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'],
],
// 可选:指定时间值来源(如 time()、date('Y-m-d H:i:s') 或表达式)
'value' => new \yii\db\Expression('NOW()'),
],
];
}⚠️ 注意:
-
EVENT_BEFORE_INSERT要同时赋值created_at和updated_at(避免插入时updated_at为 NULL); -
EVENT_BEFORE_UPDATE只需更新updated_at; - 若字段是
int类型(Unix 时间戳),把'value' => time();若是datetime/timestamp类型,用'value' => new Expression('NOW()')更可靠。
检查字段是否被规则或手动赋值覆盖
以下情况会阻止 Behavior 生效:
- 在
beforeSave()中写了$this->updated_at = ...,且没调parent::beforeSave()→ 行为被跳过; -
rules()里把updated_at设为safe,又在表单提交时传入了空值或旧值 → 覆盖了 Behavior 的自动设置; - 使用
updateAll()批量更新(绕过 AR 生命周期),Behavior 完全不触发。
✅ 建议:
- 批量更新改用
updateAll(['updated_at' => new Expression('NOW()')], $condition); - 表单提交时,对
updated_at字段不要放在 rules() 的 safe 列表里,也不要在 form 中渲染该字段; - 如需自定义逻辑,务必在
beforeSave()最后调用return parent::beforeSave($insert);
确认数据库字段允许 NULL 或有默认值
如果 updated_at 字段设为 NOT NULL 且无默认值,而 Behavior 又没生效,插入时可能报错或写入 0000-00-00 00:00:00,后续更新也难触发。
✅ 推荐建表语句片段(MySQL):
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
这样即使 PHP 层失效,数据库兜底也能保证 updated_at 更新。
验证是否真没更新?查日志和 SQL
开启 YII_DEBUG = false 时看不到日志,但可临时加一行调试:
public function beforeSave($insert)
{
\Yii::info("Before save: updated_at = {$this->updated_at}", __METHOD__);
return parent::beforeSave($insert);
}再配合开启 SQL 日志('enableLogging' => true, 'enableProfiling' => true),看实际执行的 UPDATE 语句里有没有 updated_at = ...。
不复杂但容易忽略


















