# 背景:
在做專案時,遇到一個監控需求,就是每次執行sql陳述句都要上報耗時到prometheus。首先想到的是在寫業務邏輯時每次執行sql陳述句都自己上報,但這樣會侵入業務代碼,而且有的人會忘了上報,或者上報格式不規范,所以想到將上報邏輯封裝到gorm的框架里。
# 具體原理:
gorm執行sql陳述句都是通過注冊callback函式實作的。如執行如下陳述句時:

會依次執行、queryCallback、queryCallback、queryCallback,這是因為gorm初始化時注冊了這幾個函式:

如果我們想注冊些自己寫的函式呢?而且想控制函式呼叫的順序,比如想自己注冊一個函式func2,而且在queryCallback之后,queryCallback之前呼叫,那改怎么辦?其實可以這樣:

其中after函式的引數就是注冊queryCallback時指定的名字,Register的第一個引數callbackName就是你要注冊的函式的名字,callbackName要保持唯一性,否則后面Register的會覆寫前面的。
至此,調first函式時,將會依次調這幾個函式:queryCallback、func、queryCallback、queryCallback
# 原始碼分析:
callback的定義。上面的first陳述句會把callback func append到queries欄位里。
```
// Callback is a struct that contains all CRUD callbacks
// Field `creates` contains callbacks will be call when creating object
// Field `updates` contains callbacks will be call when updating object
// Field `deletes` contains callbacks will be call when deleting object
// Field `queries` contains callbacks will be call when querying object with query methods like Find, First, Related, Association...
// Field `rowQueries` contains callbacks will be call when querying object with Row, Rows...
// Field `processors` contains all callback processors, will be used to generate above callbacks in order
type Callback struct {
logger logger
creates []*func(scope *Scope)
updates []*func(scope *Scope)
deletes []*func(scope *Scope)
queries []*func(scope *Scope)
rowQueries []*func(scope *Scope)
processors []*CallbackProcessor
}
```
這個就是first的原始碼,最后一行調callCallbacks時就會依次調queries的func。
```
// First find first record that match given conditions, order by primary key
func (s *DB) First(out interface{}, where ...interface{}) *DB {
newScope := s.NewScope(out)
newScope.Search.Limit(1)
return newScope.Set("gorm:order_by_primary_key", "ASC").
inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db
}
```
```
func (scope *Scope) callCallbacks(funcs []*func(s *Scope)) *Scope {
defer func() {
if err := recover(); err != nil {
if db, ok := scope.db.db.(sqlTx); ok {
db.Rollback()
}
panic(err)
}
}()
for _, f := range funcs {
(*f)(scope)
if scope.skipLeft {
break
}
}
return scope
}
```
參考文獻:
[http://gorm.book.jasperxu.com/callbacks.html](http://gorm.book.jasperxu.com/callbacks.html)
[https://gorm.io/docs/hooks.html](https://gorm.io/docs/hooks.html)
[Gin實踐 連載十 定制 GORM Callbacks](https://segmentfault.com/a/1190000014393602)
uj5u.com熱心網友回復:
gorm既然提供SQL log列印,就估計有提供什么介面,沒仔細研究過,剛好學習一下uj5u.com熱心網友回復:
一般會提供一些 hook類的 以供自定義函式注冊轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/144955.html
標籤:go語言
上一篇:Python中的亂序求奇數和
