为了账号安全,请及时绑定邮箱和手机立即绑定

在 Go 中通过语句或数据库使用 QueryRow

在 Go 中通过语句或数据库使用 QueryRow

Go
繁星点点滴滴 2022-05-18 14:20:43
下面的查询执行方法在 DB 中发出完全相同的(3 个)查询,这很好且易于理解 -见下文。但是,我想知道的是,就 Go 而言,两者在内存、cpu、缓存、连接使用等方面是否存在真正的区别?查询2020-02-22T12:29:23.858393Z 41 Prepare SELECT id, uuid, name FROM users WHERE id = ?2020-02-22T12:29:23.859601Z 41 Execute SELECT id, uuid, name FROM users WHERE id = 12020-02-22T12:29:23.861607Z 41 Close   stmt方法func Select1(query string, args ...interface{}) (*sql.Row, error) {    stmt, err := DB.Prepare(query)    if err != nil {        return nil, err    }    defer stmt.Close()    return stmt.QueryRow(args...), nil}func Select2(query string, args ...interface{}) *sql.Row {    return DB.QueryRow(query, args...)}
查看完整描述

2 回答

?
蓝山帝景

TA贡献1843条经验 获得超7个赞

除了@mkopriva 在关于客户端的评论中所说的内容之外,使用准备好的语句还有服务器端的影响。

重要的是要注意 using*sql.DB使用连接池

DB 是代表零个或多个底层连接池的数据库句柄

为什么这很重要?那么并发访问可能会触发多个物理连接。并且当使用准备好的语句时——它们应该被重用——只有在同一个数据库会话(即连接)上使用时才有效。

连接池(使用*sql.DB)本质上不能保证这一点。因此,如果有 100 个并发查询 - 理论上可能会生成 100 个并发数据库连接 -不是一个 - 但在服务器端最多有 100 个准备好的语句。

您可以通过sql.DB.Conn()获得与数据库的单个连接,其中:

在同一个 Conn 上运行的查询将在同一个数据库会话中运行。

这意味着任何先前生成的准备好的语句都将获得重用的好处(因为它们使用相同的“会话”)。

总之,权衡准备好的语句对客户端服务器影响的好处,以及您是否真的通过并发使用获得了这些好处。


查看完整回答
反对 回复 2022-05-18
?
MMTTMM

TA贡献1869条经验 获得超4个赞

我花了更多时间进行测试和分析,所以这是我的发现 - 也证实了@mkopriva 的评论。

如果使用SELECT语句,无论是否使用查询占位符,您都应该更喜欢使用DB.Query和/或DB.QueryRow而不是DB.Prepare&STMT.Exec组合。DB.Query当我检查 MySQL 查询日志时,它看起来就像DB.QueryRow 它们用于DB.Exec没有参数占位符的查询一样。这意味着只有一个Query) 网络往返而不是三个Prepare,ExecuteClose)!

那么为什么不直接使用DB.Exec呢?因为它用于不返回结果集的查询。顺便说一句,DB.Exec它直接释放它的连接回池,但DB.Query它的连接保持在池之外,直到rows.Close()被调用。如果您忘记调用它,这可能会导致连接“泄漏”和连接不可用。因此,从技术上讲,DB.Query如果您没有正确地做事,就会有其自身的风险。

最后要注意的是,如果您的INSERT,UPDATEDELETEquery 参数没有 SQL 注入,那么请使用DB.Execelse 来DB.Prepare代替。对于手动准备查询参数,您可以使用fmt.Sprintf()函数。


查看完整回答
反对 回复 2022-05-18
  • 2 回答
  • 0 关注
  • 393 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信