首页 > 编程语言 > go > 项目使用了 ORM,具体执行的是什么 SQL 语句总是很迷?xorm1.0 解决了
2020
04-10

项目使用了 ORM,具体执行的是什么 SQL 语句总是很迷?xorm1.0 解决了



昨天有人问,能不能讲讲 xorm,于是今天先来一篇简单的。

自定义上下文 SQL Log 需求有哪些

  • 可以使用自己的封装日志库,拓展日志输出问题,可以输出到 es(elasticsearch)等,方便日志分析。
  • 方便定位 sql 问题。
  • 集成 sql 指标监控,可以找出慢 sql,优化 sql 语句。
  • 集成链路追踪(opentracing),更清楚知道业务都执行了哪些 sql 语句。

前提是 xorm 对应版本要求 >=1.0 以上的

先看下 xorm ContextLogger interface 是什么样的?https://pkg.go.dev/xorm.io/xorm/log?tab=doc#ContextLogger

type SQLLogger interface {
 BeforeSQL(context LogContext) // only invoked when IsShowSQL is true  AfterSQL(context LogContext)  // only invoked when IsShowSQL is true } type ContextLogger interface {
 SQLLogger // 内嵌接口,主要实现这个接口,需要开启sql 输出。  Debugf(format string, v ...interface{})
 Errorf(format string, v ...interface{})
 Infof(format string, v ...interface{})
 Warnf(format string, v ...interface{})

 Level() LogLevel // 日志等级  SetLevel(l LogLevel) // 设置日志等级  ShowSQL(show ...bool)
 IsShowSQL() bool }

接下来就实现以上这些接口即可。以 logrus log 库为例, 简单实现一下。

  • golang 版本使用 go 1.13+ 以上版本, 并开启 go mod。

export GONOPROXY="xorm.io"
export GOPROXY="https://goproxy.cn,direct"
go get xorm.i/[email protected]

  • golang 日志库选择其一

目前比较使用多的日志库 logrus, zap 等开源日志库。性能都比较好,结合自己的需求,选择合适的日志库。logrus[1] doc[2]
zap[3] doc[4]

  • 安装 logrus 库依赖

go get github.com/sirupsen/logrus

关键代码实现, 需要注意的是 ContextLogger 这个接口必须都要重新实现一遍。

type LogCtx struct {
 logger   *logrus.Logger
 showSQL  bool } func NewLogCtx(l *logrus.Logger) *LogCtx {
 return &LogCtx{logger: l}
} // 可自行实现, sql 执行之前操作 func (l *LogCtx) BeforeSQL(ctx xormlog.LogContext) {} func (l *LogCtx) AfterSQL(ctx xormlog.LogContext) {
 // 转成完整sql, 方面查看。如果不需要输出完整sql的拼接。 可以直接输出,看下面注释这行即可。  // l.logger.Errorf("[SQL] %v %v - %v", ctx.SQL, ctx.Args, ctx.ExecuteTime)  fullSqlStr, err := builder.ConvertToBoundSQL(ctx.SQL, ctx.Args)
 if err != nil {
  l.logger.Errorf("[SQL] %v %v - %v", ctx.SQL, ctx.Args, ctx.ExecuteTime)
 } else {
  l.logger.Infof("[SQL] %s - %v", fullSqlStr, ctx.ExecuteTime)
 }
} func (l *LogCtx) Debugf(format string, v ...interface{}) {
 l.logger.Debugf(format, v...)
} func (l *LogCtx) Errorf(format string, v ...interface{}) {
 l.logger.Errorf(format, v...)
} func (l *LogCtx) Infof(format string, v ...interface{}) {
 l.logger.Infof(format, v...)
} func (l *LogCtx) Warnf(format string, v ...interface{}) {
 l.logger.Warnf(format, v...)
} func (l *LogCtx) Level() xormlog.LogLevel {
 return logrus2xormlogLevel[l.logger.GetLevel()]
} func (l *LogCtx) SetLevel(lv xormlog.LogLevel) {
 l.logger.SetLevel(xormlog2logrusLevel[lv])
} func (l *LogCtx) ShowSQL(show ...bool) {
 if len(show) == 0 {
  l.showSQL = true   return  }
 l.showSQL = show[0]
} func (l *LogCtx) IsShowSQL() bool {
 return l.showSQL
}

调用示例 main.go

// mysql 实例 func NewMySQL() *xorm.Engine {
  engine, err := xorm.NewEngine("mysql""dsn")
  if err != nil {
    panic(err)
  }
  logs := logrus.New()
  // 使用自定义日志实现   logctx := xormlog.NewLogCtx(logs)
  engine.SetLogger(logctx)
  // 需要开启sql输出   engine.ShowSQL(true)
  return engine
}

完整代码实现链接:xormlog[5]

总结

当然这个 sql 日志实现输出是同步的。如果有影响到返回业务数据的性能,可以改成异步输出 sql 日志。

扫码芷若 获取免费视频学习资料

编程学习

查 看2019高级编程视频教程免费获取