我在Web项目中使用了带有sqlxMySQL的非框架Go堆栈。

我想记录所有传出的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

最佳答案

sqlx具有以下接口(interface)形式的非常有趣的抽象:

  • sqlx.Execer
  • sqlx.Queryer

  • 它们在整个库中都用作接口(interface),表示将字符串用作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类型进行了大量调用,则可能不够方便。

    10-01 11:51