GORM v2 注册Callback心得

date
Apr 13, 2023
slug
Registering-Custom-Callbacks-in-GORM-v2
status
Published
tags
Golang
知识分享
summary
GORM 回调函数注册、生效顺序和全局回调生效后特定 model 特殊处理的解决方法。
type
Post
category
在 GORM v2 中,我们可以通过 Register 方法来注册自定义的回调函数,这些回调函数可以被应用于所有的 model 中。这些回调函数会在 CRUD 操作中被触发,从而让我们可以在数据操作前后进行一些自定义的处理。

GORM自带注册的回调

GORM v2 自带了一些常用的回调函数,包括 BeforeSaveAfterSaveBeforeCreateAfterCreateBeforeUpdateAfterUpdateBeforeDeleteAfterDelete。这些回调函数可以在 model 层中被使用,用于在数据操作前后进行一些自定义的处理。
这些函数被注册在包→callbacks→callbacks.go中,在编写自己的回调时可以先参考下源码。使用 Register 可以注册回调函数,Replace 可以替换对应name别名的回调函数,此外还有 Remove 可以删除已注册回调函数。
图1
图1
 
图2
图2

Register/Replace中的name字段到底是用来做什么的

在 GORM v2 的 RegisterReplace 方法中,name 字段用来指定回调函数的名称,以便在后续的回调函数操作中使用。在编写回调函数时,需要注意给回调函数取名的规范性和唯一性。这个名称和回调函数的实现是一一对应的。
一开始搞不懂这个name是怎么生效的,搞不懂与源码中注册的name时候重复了怎么办。其实很好理解这就是个别名。举个例子:
上述是自己代码中的一行,因为源码中已经使用了gorm:before_create为别名注册了 GORM 自带的回调函数,所以在上述代码中Replace作用就是将别名为gorm:before_create的回调函数改为 myFun 。注册自己的函数时候一般取名my_call:whatblabla 并用Register函数,从原理上看其实前缀取不取都没差。

同名注册回调函数

在 GORM v2 中,多次以相同别名注册回调函数,先注册的回调函数会被后注册的回调函数覆盖。
举个例子:
上述代码每行的作用都是将在 Update 位置的别名为gorm:before_update的回调函数替换为我们自己写的 myCallx ,但对一模一样的gorm:before_update进行了多次Replace,实际生效的是最后一次,在上述代码中就是myCall4最后以gorm:before_update的别名被注册上。
值得一提的是,在不同位置上可以注册相同别名,举个例子:
此时Update位置Create位置都被注册上了别名为 的回调函数

全局注册回调函数后特定model特殊处理

业务是复杂的,有些特定 model 需要在全局回调后做特殊处理,那应该如何写回调呢?
在 GORM v2 中,如果不做特殊操作,在 model 中定义了 BeforeCreate 回调函数(图3),同时又注册了一个全局的 before_create 回调函数(图4),那么这两个回调函数都会在创建记录时被触发。但同时触发后谁最后生效呢?
model中定义:
图3
图3
全局注册:
图4
图4
当然是看源码啦,首先看看 model 中的回调函数是如何生效的,在源码中 GORM 初始注册了BeforeCreate(图5),在BeforeCreate中处理了BeforeCreateInterface(图6),而我们在 model 中写的回调函数就是实现了这个 Interface(图3实现了图7)。总结一句话就是在 model 中写的回调函数实现了BeforeCreateInterfaceBeforeCreateInterface 是在GORM db 初始化的时候注册的,所以 model 中的回调函数是这样生效的。
图5
图5
图6
图6
图7
图7
所以要判断最后谁生效只要知道全局注册的回调model 中写的回调谁在最后执行就可以了,那么如何决定谁最后执行呢?看代码:
GORM 的 callback 有 Before() After() 函数,可以以此来决定注册回调函数执行的前后顺序,上一节讲了同个别名同个位置的回调函数是最后注册的生效,但注册多个不同别名的回调函数是都生效的,所以只要将model 中写的回调通过 Before() After() 排到最后生效即可。
上述语句实现的功能是在别名为 的回调函数前注册别名为 的回调函数 myFun 。所以 GORM 在 Create操作时执行的回调函数顺序: myfun1(即myFun )→ gorm:before_create (即实现BeforeCreateInterface的函数),这样就可以实现先用 myFun 进行处理,再用在 model 中写的特殊的 BeforeCreate 处理,达到特定 model 特殊处理的效果。

总结

想实现特定 model 特殊回调,特殊回调注册在GORM原生回调别名之前,接着在 model 内单独写 interface{} 即可。 关键点:Before("GORM原生回调别名")。

参考文档


© Rysi 2018 - 2026