我在Gogre和Postgresql中使用。
它在这里说,对于不返回行(插入,删除,更新)的操作,我们应该使用exec()
exec()
如果函数名称包含Query,则它被设计为询问数据库问题,并且即使它为空,也将返回一组行。不返回行的语句不应使用查询函数;他们应该使用Exec()。
然后它在这里说:
Go在幕后为您创建准备好的语句。例如,一个简单的db.Query(sql,param1,param2)的工作方式是:准备sql,然后使用参数执行该sql,最后关闭该语句。
如果 query() 在准备好的表述下使用,我为什么还要打扰使用准备好的表述呢?
query()
这是真的,你可以用db.Exec和db.Query互换执行相同的SQL语句,但是这两种方法返回不同类型的结果。如果由驱动程序实现,则返回的结果db.Exec可以告诉您查询影响了多少行,而db.Query将返回行对象。
db.Exec
db.Query
例如,假设您要执行一条DELETE语句,并且想知道该语句删除了多少行。您可以通过以下适当方式进行操作:
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)
有一个第3的方式,你可以用Postgres的热膨胀系数的组合做到这一点SELECT COUNT,db.QueryRow而row.Scan但我不认为一个例子是要说明如何不合理的做法相比时,这将是db.Exec。
SELECT COUNT
db.QueryRow
row.Scan
使用db.Execover的另一个原因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调用,因此最终导致打开的连接数增加,最终达到服务器的限制。
too many connections open
db.Rows
Close
我认为您引用的书不正确。至少在我看来,db.Query每次调用是否创建一个新的准备好的语句都取决于您使用的驱动程序。
例如,请参见queryDC(未调用by的方法的db.Query)这两个部分:不带准备语句和带准备语句。
queryDC
不管书是否正确,除非关闭返回的对象,否则除非进行一些内部缓存,否则db.Stmt创建者都是正确的。如果改为手动调用,然后缓存并重用返回的内容,则可能会提高需要经常执行的查询的性能。db.Query``Rows``db.Prepare``db.Stmt
db.Stmt
db.Query``Rows``db.Prepare``db.Stmt
要了解如何使用准备好的语句来优化性能,可以看一下官方文档:https : //www.postgresql.org/docs/current/static/sql- prepare.html