确定使用未知查询字符串中的DB.Exec还是DB.Query

时间:2019-10-02 21:41:30

标签: sql database go

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

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

您的问题并不像乍看起来那样简单。

1。让我们澄清问题

问题与pgsql / mysql / sqlite / other无关,而是与任何通用数据库驱动器有关。

因此答案必须在database/sql/driver中。 让我们走的更远。

2。 sql/driver。接口:Queryer / QueryerContextExecer / ExecerContext

模块sql/driver定义了接口:

  • Queryer / QeueryerContext-具有(*DB).Query
  • 的功能
  • Execer / ExecerContext-代表(*DB).Exec
  • 其他Pinger

请注意,每个接口在文档中均被描述为“,可以由Conn实现的可选接口”

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

3。实验验证

让我们尝试实现不能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: %v\n", 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 Registred drivers: [drvexp]
2009/11/10 23:00:00 sql.Open() success: true, error: 
2009/11/10 23:00:00 db.Ping()  success: true
2009/11/10 23:00:00 db.Close() success: true
2009/11/10 23:00:00 db.Ping()  result:  sql: database is closed

有效! 此Driver实现是:

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

4。可以彼此独立实现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

5。结论

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

  • 这些方法的行为在驱动程序之间可能会发生很大的变化

  • 通常情况下,不存在正确答案

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

    • 可以假设db.Query适用于大多数情况
    • 无法保证 Query在没有实验验证的情况下确实可以工作

谢谢您的关注!

我想这是最终答案。