buffalo 的 pop.model 默认不自动更新 updated_at,需通过 beforesave 钩子手动设置 u.updatedat = time.now().utc();update() 不触发该钩子,应改用 save() 或原生 sql,并确保数据库时区与代码一致。

Buffalo 的 pop.Model 默认不自动更新 updated_at
Buffalo 自带的 ORM 是 pop,它不会像 Rails 那样默认监听模型变更并写入 updated_at。你手动调用 Save() 时,updated_at 字段保持原值,除非显式赋值或启用钩子。
必须手动实现 updated_at 更新逻辑
Pop 不提供“自动时间戳”开关,得靠 BeforeSave 钩子干预。注意:该钩子只在 Save() 和 Create() 时触发,Update() 不走此流程 —— 这是常见误判点。
Buffalo框架 1.0.1 版本源码包下载,适合需要错误处理改进、依赖更新、render.Download 注释和 request logger 调整的 v1 项目。
- 在模型结构体中定义字段:
UpdatedAt time.Time `json:"updated_at" db:"updated_at"` - 实现
BeforeSave方法(注意接收者必须是指针):func (u *User) BeforeSave(tx *pop.Connection) error { u.UpdatedAt = time.Now() return nil } - 若还需初始化
CreatedAt,同样在BeforeCreate中赋值 - 确保数据库字段类型支持微秒(如 PostgreSQL 的
TIMESTAMP WITH TIME ZONE),否则time.Now()可能被截断
Update() 方法绕过钩子,需单独处理
直接调用 tx.Update(model) 不会触发 BeforeSave,updated_at 将不会更新。这是最常踩的坑。
- 改用
tx.Save(model)替代Update(),前提是主键已存在且你接受全量写入 - 或手动拼 SQL:
tx.RawQuery("UPDATE users SET name = ?, updated_at = NOW() WHERE id = ?", name, id).Exec() - 更稳妥的做法:封装一个
UpdateWithTimestamp()方法,在业务层统一处理
时区问题容易被忽略
time.Now() 返回本地时区时间,但数据库通常设为 UTC。如果未统一,查询时可能发现 updated_at 比实际晚/早数小时。
- 推荐在
BeforeSave中用time.Now().UTC() - 检查
database.yml是否设置了sslmode=disable之外的时区参数(如timezone=utc) - PostgreSQL 示例连接串:
postgres://user:pass@localhost/db?sslmode=disable&timezone=utc










