如何将查询记录到数据库驱动程序中?

huangapple go评论77阅读模式
英文:

How to log queries to database drivers?

问题

我正在尝试用Go语言编写一个简单的数据库应用程序,它可以访问多个数据服务器,包括MySQL、MSSQL和SqlLite3。我正在使用"database/sql"包来访问它们。

db, err := sql.Open(driver, dataSourceName)
result, err := db.Exec(
    "INSERT INTO users (name, age) VALUES (?, ?)",
    "gopher",
    27,
)

我需要将SQL查询记录到各个服务器上以进行调试和审计。我该如何实现这个功能?

英文:

I am trying to write a simple Database application in go which access multiple data servers, some MySQL, MSSQL and SqlLite3.
I am using the "database/sql" package to access them.

db, err := sql.Open(driver, dataSourceName)
result, err := db.Exec(
    "INSERT INTO users (name, age) VALUES (?, ?)",
    "gopher",
    27,
)

I need to log the SQL queries to the individual servers for debugging and auditing.
How can I achieve that?

答案1

得分: 1

假设您不想使用服务器的日志记录功能,显而易见的解决方案是将所有查询记录下来。

db, err := sql.Open(driver, dataSourceName)
log.Println(dataSourceName, "INSERT INTO users (name, age) VALUES (?, ?)", "gopher", 27)
result, err := db.Exec(
	"INSERT INTO users (name, age) VALUES (?, ?)",
	"gopher",
	27,
)

这是您问题的基本解决方案。您可以通过以下多种方式进行改进:

  • 为您的查询创建一个专门的log.Logger,以便将其定向到特定的输出目标。
  • 在一个特殊的结构中包装上述的log.Loggersql.DB对象,以在执行查询时记录它们。

以下是一个简单的示例结构:

type DB struct {
	db  *sql.DB
	dsn string
	log *log.Logger
}

func NewDB(driver, dsn string, log *log.Logger) (*DB, error) {
	db, err := sql.Open(driver, dsn)
	if err != nil {
		return nil, err
	}

	return &DB{
		db:  db,
		dsn: dsn,
		log: log,
	}, nil
}

func (d DB) Exec(query string, args ...interface{}) (sql.Result, error) {
	d.log.Println(d.dsn, query, args)
	return d.db.Exec(query, args...)
}

下面是如何使用它的示例:

l := log.New(os.Stdout, "[sql]", log.LstdFlags)

db, _ := NewDB(driver, dataSourceName, l)
result, _ := db.Exec(
	"INSERT INTO users (name, age) VALUES (?, ?)",
	"gopher",
	27,
)

显然,您可以通过添加错误报告、查询持续时间等来进一步完善这个设计。

英文:

Assuming that you don't want to use the servers logging facilities, the obvious solution would be to simply log all queries as they are made.

db, err := sql.Open(driver, dataSourceName)
log.Println(dataSourceName, "INSERT INTO users (name, age) VALUES (?, ?)", "gopher", 27)
result, err := db.Exec(
	"INSERT INTO users (name, age) VALUES (?, ?)",
	"gopher",
	27,
)

This is the basic solution for your problem. You can refine it in multiple ways:

  • Create a log.Logger exclusively for your queries, so you can direct it to a particular output destination
  • Wrap the said log.Logger and the sql.DB objects in a special struct that will log queries as they are done

Here is a rough example of the said struct:

type DB struct {
	db *sql.DB
	dsn string
	log *log.Logger
}

func NewDB(driver, dsn string, log *log.Logger) (*DB, error) {
	db, err := sql.Open(driver, dsn)
	if err != nil {
		return nil, err
	}
	
	return &DB {
		db: db,
		dsn: dsn,
		log: log,
	}
}

func (d DB) Exec(query string, args ...interface{}) (sql.Result, err) {
	d.log.Println(dsn, query, args)
	return d.db.Exec(query, args...)
}

And how you would use it:

l := log.New(os.Stdout, "[sql]", log.LstdFlags)

db, _ := NewDB(driver, dataSourceName, l)
result, _ := db.Exec(
	"INSERT INTO users (name, age) VALUES (?, ?)",
	"gopher",
	27,
)

Obviously, you can refined this design again, by adding error reporting, duration of the queries, etc.

答案2

得分: 0

现在有一种解决方案,可以在不使用添加日志的包装器的情况下解决这个问题。

sqldblogger 可以在不改变现有 sql.DB 代码的情况下实现这一点。

英文:

There is now a solution for that without having to wrap sql.DB with a wrapper that adds the logging.

sqldblogger facilitates this without needing to change existing sql.DB code.

huangapple
  • 本文由 发表于 2015年3月26日 11:15:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/29270501.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定