项目使用了 ORM,具体执行的是什么 SQL 语句总是很迷?xorm1.0 解决了(项目使用了多少个springboot服务器)

网友投稿 306 2022-07-07

昨天有人问,能不能讲讲 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/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最优秀的验证库(go的过去式)
下一篇:八个字节的 UDP 如何传输数据(八个字节的二进制位)
相关文章

 发表评论

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