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

网友投稿 1374 2022-08-19

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

项目使用了 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-,direct"

go get xorm.i/xorm@v1.0.0

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 日志。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Go 每日一库之 validator:Go最优秀的验证库(goal)
下一篇:八个字节的 UDP 如何传输数据(8个字节表示)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~