timestampbehavior未生效导致created_at和updated_at未自动写入,需显式配置behavior、字段名严格匹配、用expression('now()')、数据库字段default设为null、避免save(false)或insert()绕过事件。

AR 新增记录时 created_at 和 updated_at 没有自动写入,不是框架坏了,而是 TimestampBehavior 没配对、没生效,或者数据库字段类型/默认值干扰了行为逻辑。
TimestampBehavior 必须显式声明才能工作
Yii 的 ActiveRecord 不默认处理时间戳字段,哪怕你数据库里写了 DEFAULT CURRENT_TIMESTAMP,AR 层也完全不感知——它只认自己配置的 behavior。
- 必须在模型中引入
use yii\behaviors\TimestampBehavior; - 必须重写
behaviors()方法并返回包含该 behavior 的数组 -
createdAtAttribute和updatedAtAttribute值要严格匹配数据库字段名(大小写敏感) - 漏掉任意一项,
beforeInsert就不会触发赋值
value 用 Expression('NOW()') 还是闭包函数?
推荐优先用 new \yii\db\Expression('NOW()'),而不是 function(){ return date(...); }。
-
Expression把计算下推到数据库执行,避免 PHP 时区与 MySQL 时区不一致导致的时间偏差 - 闭包函数依赖
date_default_timezone_set(),且在批量插入时可能因系统时间微差造成秒级不一致 - 若字段是
TIMESTAMP类型,MySQL 会自动转时区;用DATETIME+Expression('NOW()')更可控 - 别写
'value' => time()—— 这个值在类加载时就被固化,所有记录都变成同一个时间戳
数据库字段定义会覆盖 AR 行为
如果数据库字段本身设了 DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,反而会让 AR 的 TimestampBehavior 失效或产生冲突。
- AR 插入时若没显式给
created_at赋值,而字段又有 DEFAULT,则 MySQL 自己填,AR 的 behavior 根本不触发 - 更糟的是:behavior 试图写
NULL或空字符串进去,会被 MySQL 拦截并静默替换为当前时间,但 AR 模型里读不到这个值 - 解决方案:把字段 DEFAULT 改为
NULL,让 AR 完全掌控填充逻辑 - 验证方式:插入后立刻
var_dump($model->created_at),看是否已赋值,而不是只查数据库
为什么新增成功了,但 created_at 还是 NULL?
常见真凶不是 behavior 写错了,而是你调用了 save(false) 或设置了 $model->scenario = 'xxx' 却没在 behavior 的 attributes 里声明对应场景。
-
save(false)会跳过所有 validation 和 beforeXXX events,behavior 的EVENT_BEFORE_INSERT直接被绕过 - 如果自定义了 scenario,需显式指定 behavior 生效的事件和属性映射:
'attributes' => [ActiveRecord::EVENT_BEFORE_INSERT => ['created_at']] - 检查是否误用了
insert()方法——它不触发 AR 生命周期事件,behavior 完全无效 - 用
getDirtyAttributes()打印看看created_at是否在变更列表里,能快速定位是没赋值还是被过滤了
最易忽略的一点:behavior 配置写在父类里,但子类没调用 parent::behaviors(),导致配置被整个覆盖。别嫌烦,每个模型都该显式 return 合并后的 behaviors 数组。











