使用"database/sql
",sql.DB.Exec()
用于不返回行的查询(insert, delete, update
(,sql.DB.Query(
用于返回行(selects
(的查询。 假设您有一个要执行的传入查询字符串,但是您不知道查询是否打算返回行。 你能想到一种方法来找出是使用 Exec 还是查询吗?
在任何情况下,都不要尝试解析SQL,因为它很笨拙。如果您不确定,只需使用Query
,Query
应该能够很好地处理C_UD并在这种情况下返回一个空结果集。Query
和Exec
应该具有完全相同的效果,它们只是反应不同。仅当 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驱动程序。
实验验证
让我们尝试实现无法Query
和Exec
的正确数据库驱动程序: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
角度来看是正确的 - 没有工作方法
Query
和Exec
(尝试会引发恐慌( - 令人惊讶的工作
Ping()
可以彼此独立地实现Exec
或Query
让我们添加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
真的会起作用
- 可以假设
感谢您的关注!
我想这是最终的答案。