我如何记录Go / MySQL的所有出站SQL语句?

18

我正在使用非框架的Go技术栈,结合sqlxMySQL来进行Web项目开发。

我想要记录所有外发SQL语句以进行调试,这是否可行?希望能获得类似于以下输出(从Rails项目中复制):

  User Load (94.4ms)  SELECT `users`.* FROM `users` WHERE `users`.`login` = 'bondnewyork' LIMIT 1
  User Load (16.3ms)  SELECT `users`.* FROM `users` WHERE `users`.`login` = 'mkovarik' LIMIT 1
  User Load (0.3ms)  SELECT `users`.* FROM `users` WHERE `users`.`login` = 'mkovarik' LIMIT 1
  User Load (0.3ms)  SELECT `users`.* FROM `users` ORDER BY `users`.`id` DESC LIMIT 1
  User Load (0.4ms)  SELECT `users`.* FROM `users` ORDER BY `users`.`id` DESC LIMIT 1

你想在“服务器”端还是在MySQL端执行它? - ravnur
服务器端更可取。 - Sonny Saluja
如果您正在实现项目,可以在应用程序中创建一个入口点来使用sqlx,并在那里进行日志记录。这对您有帮助吗? - ravnur
1
我们在很多地方调用了sqlx的API,但这对我来说并不是一个非常吸引人的解决方案。 - Sonny Saluja
1个回答

22
SQLX 在以下接口中实现了非常有趣的抽象: 这些接口在整个库中被用作以字符串形式表示 SQL 查询功能的接口。
例如:
db, err := sqlx.Connect("postgres", "user=foo dbname=bar sslmode=disable")
if err != nil {
    log.Fatalln(err)
}

// exec the schema or fail; multi-statement Exec behavior varies between
// database drivers;  pq will exec them all, sqlite3 won't, ymmv
db.MustExec("CREATE TABLE person (first_name text)")

实际上,最后一行等同于:

sqlx.MustExec(db, "CREATE TABLE person (first_name text)")

在使用 db 作为 Execer 的情况下:

同样地,这个例子也是如此:

people := []Person{}
db.Select(&people, "SELECT * FROM person ORDER BY first_name ASC")

相当于:

sqlx.Select(db, &people, "SELECT * FROM person ORDER BY first_name ASC")

在这里,db 被用作 Queryer

如果你不想直接使用 DB 类型,而是使用库中底层的自由函数,你可以使用以下结构将你的 db 包装成执行日志记录的对象:

type QueryLogger struct {
    queryer sqlx.Queryer
    logger  *log.Logger
}

func (p *QueryLogger) Query(query string, args ...interface{}) (*sql.Rows, error) {
    p.logger.Print(query, args...)
    return p.queryer.Query(query, args...)
}

func (p *QueryLogger) Queryx(query string, args ...interface{}) (*Rows, error) {
    p.logger.Print(query, args...)
    return p.queryer.Queryx(query, args...)
}

func (p *QueryLogger) QueryRowx(query string, args ...interface{}) *Row {
    p.logger.Print(query, args...)
    return p.queryer.QueryRowx(query, args...)
}

当连接到您的数据库时:

db, err := sqlx.Connect("postgres", "user=foo dbname=bar sslmode=disable")
if err != nil {
    log.Fatalln(err)
}

ql := &QueryLogger{db, yourLogger}

sqlx.Select(ql, &people, "SELECT * FROM person ORDER BY first_name ASC")

当然,这只适用于使用sqlx库的免费函数时。如果你的代码有大量调用sqlx.DB类型的函数,则这可能不太方便。

我在带参数的查询中遇到了困难,例如:("select * from item where id=?", nId)。我得到的结果是:select * from item where id=?%!(EXTRA int=2)。Logger.Printf不理解字符'?'。请帮忙解决。 - Ram Ashish Pal
@RamAshishPal 我提供了一个非常基本的实现来记录日志。如果你想用实际值替换'?'参数,你需要手动解析SQL字符串并自己进行替换。如果你需要帮助编写这个函数,你应该提出一个新的问题。 - SirDarius

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接