W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
自定義回調(diào)處理是最常見的接口開發(fā)實現(xiàn),我們往往只需要對接口中的部分實現(xiàn)進行替換修改,以在原有的實現(xiàn)邏輯中注入自定義的邏輯實現(xiàn)。我們來看一個自定義回調(diào)處理的示例,我們需要將所有執(zhí)行的?SQL
?語句記錄到?monitor
?表中,以方便于進行?SQL
?審計。
為簡化示例編寫,我們這里實現(xiàn)了一個自定義的?MySQL
?驅(qū)動,該驅(qū)動繼承于?gdb
?模塊中已經(jīng)實現(xiàn)的?DriverMysql
?,并按照需要修改覆蓋相應(yīng)的接口方法。由于所有的?SQL
?語句執(zhí)行必定會通過?DoQuery
?或者?DoExec
?接口,因此我們在自定義的驅(qū)動中實現(xiàn)并覆蓋這兩個接口方法即可。
package driver
import (
"context"
"database/sql"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/os/gtime"
)
// MyDriver is a custom database driver, which is used for testing only.
// For simplifying the unit testing case purpose, MyDriver struct inherits the mysql driver
// gdb.DriverMysql and overwrites its functions DoQuery and DoExec.
// So if there's any sql execution, it goes through MyDriver.DoQuery/MyDriver.DoExec firstly
// and then gdb.DriverMysql.DoQuery/gdb.DriverMysql.DoExec.
// You can call it sql "HOOK" or "HiJack" as your will.
type MyDriver struct {
*gdb.DriverMysql
}
var (
// customDriverName is my driver name, which is used for registering.
customDriverName = "MyDriver"
)
func init() {
// It here registers my custom driver in package initialization function "init".
// You can later use this type in the database configuration.
if err := gdb.Register(customDriverName, &MyDriver{}); err != nil {
panic(err)
}
}
// New creates and returns a database object for mysql.
// It implements the interface of gdb.Driver for extra database driver installation.
func (d *MyDriver) New(core *gdb.Core, node *gdb.ConfigNode) (gdb.DB, error) {
return &MyDriver{
&gdb.DriverMysql{
Core: core,
},
}, nil
}
// DoQuery commits the sql string and its arguments to underlying driver
// through given link object and returns the execution result.
func (d *MyDriver) DoQuery(ctx context.Context, link gdb.Link, sql string, args ...interface{}) (rows *sql.Rows, err error) {
tsMilli := gtime.TimestampMilli()
rows, err = d.DriverMysql.DoQuery(ctx, link, sql, args...)
link.Exec(
"INSERT INTO `monitor`(`sql`,`cost`,`time`,`error`) VALUES(?,?,?,?)",
gdb.FormatSqlWithArgs(sql, args),
gtime.TimestampMilli()-tsMilli,
gtime.Now(),
err,
)
return
}
// DoExec commits the query string and its arguments to underlying driver
// through given link object and returns the execution result.
func (d *MyDriver) DoExec(ctx context.Context, link gdb.Link, sql string, args ...interface{}) (result sql.Result, err error) {
tsMilli := gtime.TimestampMilli()
result, err = d.DriverMysql.DoExec(ctx, link, sql, args...)
link.Exec(
"INSERT INTO `monitor`(`sql`,`cost`,`time`,`error`) VALUES(?,?,?,?)",
gdb.FormatSqlWithArgs(sql, args),
gtime.TimestampMilli()-tsMilli,
gtime.Now(),
err,
)
return
}
// DoFilter is a hook function, which filters the sql and its arguments before it's committed to underlying driver.
// The parameter `link` specifies the current database connection operation object. You can modify the sql
// string `sql` and its arguments `args` as you wish before they're committed to driver.
func (d *MyDriver) DoFilter(ctx context.Context, link gdb.Link, sql string, args []interface{}) (newSql string, newArgs []interface{}, err error) {
//Filter sql Step1
sql_new := gstr.Replace(sql, "\n", "")
//Filter sql Step2
sql_new = gstr.Replace(sql_new, "\t", "")
//... Filter what you want ...
//Filter args Step1
for _, v := range args {
switch v.(type) {
case gdb.Map:
//Do it what you wan
case string:
//Do it what you wan
}
}
return sql_new, args, nil
}
func (d *MyDriver) ConvertDataForRecord(ctx context.Context, data interface{}) map[string]interface{} {
//this hook is convert data to map[string]interface{}
result := make(map[string]interface{}, 0)
//like this
switch data.(type) {
case gdb.Map:
result = gconv.Map(data)
case gdb.List:
for k, v := range data.(gdb.List) {
result[strconv.Itoa(k)] = gconv.Map(v)
}
//case other type,do it what you want
}
return result
}
我們看到,這里在包初始化方法?init
?中使用了?gdb.Register("MyDriver", &MyDriver{})
?來注冊了了一個自定義名稱的驅(qū)動。我們也可以通過?gdb.Register("mysql", &MyDriver{})
?來覆蓋已有的框架?mysql
?驅(qū)動為自己的驅(qū)動。
驅(qū)動名稱?mysql
?為框架默認的?DriverMysql
?驅(qū)動的名稱。
由于這里我們使用了一個新的驅(qū)動名稱?MyDriver
?,因此在?gdb
?配置中的?type
?數(shù)據(jù)庫類型時,需要填寫該驅(qū)動名稱。以下是一個使用配置的示例:
database:
default:
- link: "MyDriver:root:12345678@tcp(127.0.0.1:3306)/user"
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: