我在Postgresql中使用golang。
它表示here对于不返回行(插入,删除,更新)的操作,我们应该使用exec()
如果函数名称包含Query,则它旨在询问数据库的问题,并返回一组行,即使它是空的。不返回行的语句不应使用Query函数;他们应该使用Exec()。
然后它说here:
Go为您创建准备好的陈述。例如,一个简单的db.Query(sql,param1,param2)通过准备sql,然后使用参数执行它并最终关闭语句来工作。
如果 query()
使用了封面准备好的陈述,为什么我还要打扰使用准备好的陈述?
答案 0 :(得分:11)
确实可以交替使用db.Exec
和db.Query
来执行相同的sql语句,但这两种方法会返回不同类型的结果。如果由驱动程序实现,则从db.Exec
返回的结果可以告诉您查询影响了多少行,而db.Query
将返回行对象。
例如,假设您要执行DELETE
语句,并且想知道它删除了多少行。你可以采用正确的方式:
res, err := db.Exec(`DELETE FROM my_table WHERE expires_at = $1`, time.Now())
if err != nil {
panic(err)
}
numDeleted, err := res.RowsAffected()
if err != nil {
panic(err)
}
print(numDeleted)
或者更冗长,更客观更昂贵的方式:
rows, err := db.Query(`DELETE FROM my_table WHERE expires_at = $1 RETURNING *`, time.Now())
if err != nil {
panic(err)
}
defer rows.Close()
var numDelete int
for rows.Next() {
numDeleted += 1
}
if err := rows.Err(); err != nil {
panic(err)
}
print(numDeleted)
你可以通过postgres CTE,SELECT COUNT
,db.QueryRow
和row.Scan
来实现这一目标,但我不认为有必要展示一个不合理的例子。与db.Exec
相比时的方法。
使用db.Exec
超过db.Query
的另一个原因是,当您不关心返回的结果时,您需要的只是执行查询并检查是否存在错误。在这种情况下,您可以这样做:
if _, err := db.Exec(`<my_sql_query>`); err != nil {
panic(err)
}
另一方面,你不能(你可以,但你不应该)这样做:
if _, err := db.Query(`<my_sql_query>`); err != nil {
panic(err)
}
这样做,片刻之后,您的程序会因为出现与too many connections open
类似的错误而惊慌失措。这是因为您在没有首先对其进行强制db.Rows
调用的情况下丢弃返回的Close
值,因此您最终会打开连接数并最终达到服务器限制。< / p>
我不认为你引用的那本书是正确的。至少在我看来,db.Query
调用是否每次创建一个新的预准备语句都取决于您使用的驱动程序。
例如,请参阅queryDC
的两个部分(由db.Query
调用的未导出方法):without prepared statement和with prepared statement。
无论本书是否正确,db.Stmt
创建的db.Query
都是,除非有一些内部缓存,否则在关闭返回的Rows
对象后会被丢弃。如果您改为手动调用db.Prepare
,然后缓存并重新使用返回的db.Stmt
,则可以提高需要经常执行的查询的性能。
要了解准备好的声明如何用于优化性能,您可以查看官方文档:https://www.postgresql.org/docs/current/static/sql-prepare.html