为什么无法根据已经执行的准备好的语句从池中为连接提供服务?

Why is it impossible to serve connections from pool according to the prepared statement already executed with them?

我一直在网上研究设计连接池的最有效方法,并尝试详细分析可用的库(HikariCP、BoneCP 等)。

我们的应用程序是一个重负载的消费者网络应用程序,大部分时间用户都在处理类似的业务对象(因此执行的底层 SQL 查询通常是相同的,但仍然有很多) . 它设计用于不同的 DBMS(尤其是 Oracle 和 MS SQL 服务器)。

所以一个简化的用例是:

如果我们想利用底层 JDBC 驱动程序的 Prepared Statement 缓存(因为 PStatements 附加到连接 - jTDS doc.),根据我的理解,最佳的做法是它将是:

我是否遗漏了重要的一点(例如 JDBC 驱动程序能够重用缓存语句而不管连接如何)或者我的分析是否正确?

不同 sources 我发现状态是不可能的,但为什么?

要使您的方案生效,您需要能够获得已经准备好该语句的连接。

这有两点犯规:

  1. 在JDBC中先获取连接,
  2. 缓存的准备好的语句(如果驱动程序或连接池甚至支持它)不会以标准化方式公开(如果有的话),您也无法反省它们。

寻找正确连接的性能开销(以及随后对已经准备好的少数连接的争用)可能会抵消重用准备好的语句的任何好处。

另请注意,一些数据库系统也有一个用于准备好的语句的服务器端缓存(意味着它已经有可用的计划等),限制了来自客户端的新准备的开销。

如果您真的认为性能优势足够大,您应该考虑使用特定于此功能的数据源(因此几乎可以保证连接将在其缓存中包含该语句)。

一个解决方案可能是连接池实现延迟从池中检索连接,直到 Connection.prepareStatement() 被调用。那时,连接池将通过 SQL 语句文本查找可用连接,然后转发在 Connection.prepareStatement() 之前进行的所有调用。这样就可以与准备好的 PreparedStatement 建立联系,而不会出现其他人提出的问题。

换句话说,当您从池中请求连接时,它将 return 一个包装器,记录所有内容,直到第一个需要数据库访问的操作(例如请求 prepareStatement() 被请求。

您需要咨询连接池功能的供应商才能添加此功能。

我用 C3P0 记录了这个请求:

https://github.com/swaldman/c3p0/issues/55

希望对您有所帮助。