确定是否使用数据库.执行或数据库.来自未知查询字符串的查询



使用"database/sql",sql.DB.Exec()用于不返回行的查询(insert, delete, update(,sql.DB.Query(用于返回行(selects(的查询。 假设您有一个要执行的传入查询字符串,但是您不知道查询是否打算返回行。 你能想到一种方法来找出是使用 Exec 还是查询吗?

在任何情况下,都不要尝试解析SQL,因为它很笨拙。如果您不确定,只需使用QueryQuery应该能够很好地处理C_UD并在这种情况下返回一个空结果集。QueryExec应该具有完全相同的效果,它们只是反应不同。仅当 API 的用户明确不需要结果时才使用Exec

你的问题并不像乍一看那么简单。

让我们澄清一下问题:

问题不是关于特定数据库作为pgsql/mysql/sqlite/other,而是针对任何通用数据库驱动器。

所以答案一定是database/sql/driver.

让我们更进一步:

sql/driver.接口:Queryer/QueryerContext&Execer/ExecerContext

模块sql/driver定义接口:

  • Queryer/QueryerContext- 用于(*DB).Query能力
  • Execer/ExecerContext- 用于(*DB).Exec
  • 其他如Pinger

请注意,文档中描述的每个接口都为"可由 Conn 实现的可选接口">

这意味着可以在没有Query和/或Exec的情况下实现sql驱动程序。

实验验证

让我们尝试实现无法QueryExec的正确数据库驱动程序:https://play.golang.org/p/sZiigEghphE

package main
import (
"database/sql"
"database/sql/driver"
"log"
)
type expdrv struct{}
type expconn struct{}
// sql.Driver implementation
func (*expdrv) Open(name string) (driver.Conn, error) {
return &expconn{}, nil
}
// driver.Conn implementation
func (c *expconn) Prepare(query string) (driver.Stmt, error) {
return nil, nil
}
func (c *expconn) Close() error {
return nil
}
func (c *expconn) Begin() (driver.Tx, error) {
return nil, nil
}
func main() {
sql.Register("drvexp", &expdrv{})
log.Printf("Registred drivers: %vn", sql.Drivers())
db, err := sql.Open("drvexp", "")
log.Printf("sql.Open() success: %v, error: %v", db != nil, err)
log.Println("db.Close() error:", db.Close())
}
2009/11/10 23:00:00 注册驱动程序: [drvexp] 2009/11/10 23:00:00 sql.Open(( 成功: 真, 错误: 2009/11/10 23:00:00 db.Ping(( 成功:真 2009/11/10 23:00:00 db.关闭(( 成功:真 2009/11/10 23:00:00 db.Ping(( 结果: sql: 数据库已关闭

它有效!

Driver实现为:

  • database/sql角度来看是正确的
  • 没有工作方法QueryExec(尝试会引发恐慌(
  • 令人惊讶的工作Ping()

可以彼此独立地实现ExecQuery

让我们添加Exec

// driver.Result & driver.Execer
type expresult struct{}
func (*expconn) Exec(query string, args []driver.Value) (driver.Result, error) {
return &expresult{}, nil
}
func (*expresult) LastInsertId() (int64, error) {
return 0, nil
}
func (*expresult) RowsAffected() (int64, error) {
return 0, nil
}

将允许:

_, err = db.Exec("BYE")
fmt.Println("db.Exec() success:", err == nil) // Outputs: true

结论

  • 呼叫Query/QueryContext和/或Exec/ExecContext的功能是可选的

  • 这些方法的行为在驱动程序之间可能会有很大差异

  • 在一般情况下,没有正确的答案存在

  • 对于特定情况(使用特定驱动程序(:

    • 可以假设db.Query在大多数情况下都有效
    • 但是,如果没有实验验证,就不可能保证Query真的会起作用

感谢您的关注!

我想这是最终的答案。

最新更新