2 回答
TA贡献1843条经验 获得超7个赞
除了@mkopriva 在关于客户端的评论中所说的内容之外,使用准备好的语句还有服务器端的影响。
重要的是要注意 using*sql.DB使用连接池:
DB 是代表零个或多个底层连接池的数据库句柄
为什么这很重要?那么并发访问可能会触发多个物理连接。并且当使用准备好的语句时——它们应该被重用——只有在同一个数据库会话(即连接)上使用时才有效。
连接池(使用*sql.DB)本质上不能保证这一点。因此,如果有 100 个并发查询 - 理论上可能会生成 100 个并发数据库连接 -不是一个 - 但在服务器端最多有 100 个准备好的语句。
您可以通过sql.DB.Conn()获得与数据库的单个连接,其中:
在同一个 Conn 上运行的查询将在同一个数据库会话中运行。
这意味着任何先前生成的准备好的语句都将获得重用的好处(因为它们使用相同的“会话”)。
总之,权衡准备好的语句对客户端和服务器影响的好处,以及您是否真的通过并发使用获得了这些好处。
TA贡献1869条经验 获得超4个赞
我花了更多时间进行测试和分析,所以这是我的发现 - 也证实了@mkopriva 的评论。
如果使用SELECT语句,无论是否使用查询占位符,您都应该更喜欢使用DB.Query和/或DB.QueryRow而不是DB.Prepare&STMT.Exec组合。DB.Query当我检查 MySQL 查询日志时,它看起来就像DB.QueryRow 它们用于DB.Exec没有参数占位符的查询一样。这意味着只有一个( Query) 网络往返而不是三个( Prepare,Execute和Close)!
那么为什么不直接使用DB.Exec呢?因为它用于不返回结果集的查询。顺便说一句,DB.Exec它直接释放它的连接回池,但DB.Query它的连接保持在池之外,直到rows.Close()被调用。如果您忘记调用它,这可能会导致连接“泄漏”和连接不可用。因此,从技术上讲,DB.Query如果您没有正确地做事,就会有其自身的风险。
最后要注意的是,如果您的INSERT,UPDATE和DELETEquery 参数没有 SQL 注入,那么请使用DB.Execelse 来DB.Prepare代替。对于手动准备查询参数,您可以使用fmt.Sprintf()函数。
- 2 回答
- 0 关注
- 537 浏览
添加回答
举报
