插件必须实现gorm.Plugin接口(含Register(*gorm.DB) error方法)才能被db.Use()加载,否则会panic;直接注册callback不满足该接口要求,无法通过db.Use调用。

插件必须实现 gorm.Plugin 接口才能被 db.Use() 加载
直接往 db.Callbacks 里注册函数,哪怕逻辑完全正确,db.Use(&MyPlugin{}) 也会 panic——因为 GORM 只认实现了 Register(*gorm.DB) error 方法的类型。这是最常卡住的第一步。
常见错误现象:panic: plugin must implement gorm.Plugin interface
- 结构体不能是空的,哪怕只写
type MyPlugin struct{}也得补上Register方法 -
Register方法签名必须严格为func (p MyPlugin) Register(*gorm.DB) error,返回值不能省略 - 方法内不能做阻塞操作(如建表、HTTP 请求),否则会拖慢整个应用启动
- 插件实例本身不应带状态,所有上下文应通过
tx.Statement.Context或tx.InstanceSet存储
db.Use() 的作用域仅限于当前 *gorm.DB 实例,不透传到子 session
你在主 db 上调用 db.Use(&TimestampPlugin{}),后续用 db.Session(&gorm.Session{}) 或 db.WithContext(ctx) 创建的新实例,默认没有该插件——GORM 不自动继承。
使用场景:微服务中按租户切换 DB 实例、单元测试中隔离事务、读写分离时复用主库插件但禁用从库钩子。
- 需要子 session 也有插件?手动再调一次
childDB.Use(&plugin) - 想全局生效?只能在每个新生成的
*gorm.DB实例初始化时统一Use - 别依赖
db.Session().Use()——Session()返回值不支持链式Use
Callback 函数签名必须是 func(*gorm.DB),且只能通过 tx.Statement.Schema 拿模型信息
你不能在 callback 里直接访问原始 struct 字段,也不能传额外参数(比如 logger、config)。一切模型元信息都得从 tx.Statement.Schema 里查。
容易踩的坑:误以为 tx.Statement.ReflectValue 是当前 model 实例,其实它可能是 nil(比如在 Query 阶段未加载数据时);或者遍历 Schema.Fields 时没判空,导致 panic。
- 安全获取字段值:用
field.ValueOf(tx.Statement.ReflectValue),它会返回(interface{}, bool) - 改字段值:用
tx.Statement.SetColumn(field.Name, value),不是field.Set(...) - 判断是否是 Create/Update/Query:看
tx.Statement.Settings或tx.Statement.Clauses,而不是靠函数名 - 避免硬编码字段名,用
schema.LookUpField("created_at")更健壮
插件适合跨 model 复用,单 model 钩子优先用 BeforeCreate 等 struct tag
如果你只是给 User 模型加个 updated_at 自动更新,写插件是杀鸡用牛刀。GORM 提供了更轻量的方式:UpdatedAt tag 或 BeforeUpdate 方法。
真正该写插件的信号:逻辑要同时作用于 User、Order、Product;需要统一审计日志字段;要和第三方 SDK(如 Sentry、OpenTelemetry)集成;或需控制回调执行顺序(比如必须在 gorm:before_create 之前触发)。
- tag 示例:
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime"` - 方法示例:
func (u *User) BeforeCreate(tx *gorm.DB) error { u.CreatedAt = time.Now(); return nil } - 插件优势:可开关、可配置、可测试、可发布为独立 module(如
gorm-soft-delete)
复杂点在于插件注册时机与作用域的耦合性——它不像 middleware 那样天然支持“继承”,也不像 struct tag 那样声明即生效。你得明确知道:这个插件是绑在 DB 实例上,还是每次查询前动态注入,抑或由某个中间层统一管理。漏掉其中一环,功能就静默失效。











