Files

177 lines
5.1 KiB
Go
Raw Permalink Normal View History

2025-08-03 00:11:15 +08:00
package database
import (
"context"
"database/sql/driver"
"time"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"nl-video-api/utility/logger"
)
// SQLHook SQL执行钩子用于记录SQL日志和错误
type SQLHook struct{}
// BeforeQuery 查询前钩子
func (h *SQLHook) BeforeQuery(ctx context.Context, link gdb.Link, sql string, args []interface{}) (context.Context, error) {
// 记录查询开始时间
ctx = context.WithValue(ctx, "sql_start_time", time.Now())
return ctx, nil
}
// AfterQuery 查询后钩子
func (h *SQLHook) AfterQuery(ctx context.Context, link gdb.Link, sql string, args []interface{}, result gdb.Result, err error) error {
// 计算执行时间
startTime, ok := ctx.Value("sql_start_time").(time.Time)
var duration time.Duration
if ok {
duration = time.Since(startTime)
}
// 获取影响行数
var rowsAffected int64
if result != nil {
rowsAffected = int64(result.Len())
}
if err != nil {
// 记录SQL执行错误
logger.LogDatabaseError(ctx, "Query", sql, err)
logger.LogError(ctx, "SQL查询失败 | SQL: %s | Args: %v | Duration: %v | Error: %v",
sql, args, duration, err)
} else {
// 记录SQL执行成功
logger.LogDatabaseQuery(ctx, sql, args, duration, rowsAffected)
}
return err
}
// BeforeExec 执行前钩子
func (h *SQLHook) BeforeExec(ctx context.Context, link gdb.Link, sql string, args []interface{}) (context.Context, error) {
// 记录执行开始时间
ctx = context.WithValue(ctx, "sql_start_time", time.Now())
return ctx, nil
}
// AfterExec 执行后钩子
func (h *SQLHook) AfterExec(ctx context.Context, link gdb.Link, sql string, args []interface{}, result driver.Result, err error) error {
// 计算执行时间
startTime, ok := ctx.Value("sql_start_time").(time.Time)
var duration time.Duration
if ok {
duration = time.Since(startTime)
}
// 获取影响行数
var rowsAffected int64
if result != nil {
if affected, e := result.RowsAffected(); e == nil {
rowsAffected = affected
}
}
if err != nil {
// 记录SQL执行错误
logger.LogDatabaseError(ctx, "Exec", sql, err)
logger.LogError(ctx, "SQL执行失败 | SQL: %s | Args: %v | Duration: %v | Error: %v",
sql, args, duration, err)
} else {
// 记录SQL执行成功
logger.LogDatabaseQuery(ctx, sql, args, duration, rowsAffected)
}
return err
}
// BeforePrepare 预处理前钩子
func (h *SQLHook) BeforePrepare(ctx context.Context, link gdb.Link, sql string) (context.Context, error) {
return ctx, nil
}
// AfterPrepare 预处理后钩子
func (h *SQLHook) AfterPrepare(ctx context.Context, link gdb.Link, sql string, stmt *gdb.Stmt, err error) error {
if err != nil {
logger.LogDatabaseError(ctx, "Prepare", sql, err)
logger.LogError(ctx, "SQL预处理失败 | SQL: %s | Error: %v", sql, err)
}
return err
}
// BeforeCommit 提交前钩子
func (h *SQLHook) BeforeCommit(ctx context.Context, link gdb.Link) (context.Context, error) {
logger.LogSQL(ctx, "事务提交开始")
return ctx, nil
}
// AfterCommit 提交后钩子
func (h *SQLHook) AfterCommit(ctx context.Context, link gdb.Link, err error) error {
if err != nil {
logger.LogError(ctx, "事务提交失败 | Error: %v", err)
} else {
logger.LogSQL(ctx, "事务提交成功")
}
return err
}
// BeforeRollback 回滚前钩子
func (h *SQLHook) BeforeRollback(ctx context.Context, link gdb.Link) (context.Context, error) {
logger.LogSQL(ctx, "事务回滚开始")
return ctx, nil
}
// AfterRollback 回滚后钩子
func (h *SQLHook) AfterRollback(ctx context.Context, link gdb.Link, err error) error {
if err != nil {
logger.LogError(ctx, "事务回滚失败 | Error: %v", err)
} else {
logger.LogSQL(ctx, "事务回滚成功")
}
return err
}
// InitDatabaseHook 初始化数据库钩子
func InitDatabaseHook() {
// 获取默认数据库实例
db := g.DB()
// 添加SQL执行钩子
db.AddHook(&SQLHook{})
logger.LogInfo(context.Background(), "数据库钩子初始化完成")
}
// LogDatabaseConnection 记录数据库连接日志
func LogDatabaseConnection(ctx context.Context, config gdb.ConfigNode, err error) {
if err != nil {
logger.LogError(ctx, "数据库连接失败 | Host: %s | Database: %s | Error: %v",
config.Host, config.Name, err)
} else {
logger.LogInfo(ctx, "数据库连接成功 | Host: %s | Database: %s",
config.Host, config.Name)
}
}
// LogDatabasePing 记录数据库ping日志
func LogDatabasePing(ctx context.Context, duration time.Duration, err error) {
if err != nil {
logger.LogError(ctx, "数据库ping失败 | Duration: %v | Error: %v", duration, err)
} else {
logger.LogInfo(ctx, "数据库ping成功 | Duration: %v", duration)
}
}
// LogTransactionStart 记录事务开始日志
func LogTransactionStart(ctx context.Context, txId string) {
logger.LogSQL(ctx, "事务开始 | TxID: %s", txId)
}
// LogTransactionEnd 记录事务结束日志
func LogTransactionEnd(ctx context.Context, txId string, success bool, duration time.Duration) {
if success {
logger.LogSQL(ctx, "事务结束(成功) | TxID: %s | Duration: %v", txId, duration)
} else {
logger.LogError(ctx, "事务结束(失败) | TxID: %s | Duration: %v", txId, duration)
}
}