2010-05-27 58 views
17

我们正在运行java6/hibernate/c3p0/postgresql堆栈。 我们的JDBC驱动程序是8.4-701.jdbc3我应该激活c3p0语句池吗?

我对准备语句有几个问题。我已阅读 优秀文档约Prepared Statements

但我仍然有一个问题,如何配置PostgreSQL的c3p0。

目前,我们有

c3p0.maxStatements = 0 
c3p0.maxStatementsPerConnection = 0 

在我的理解中准备的语句和语句池是两个不同的东西:

我们休眠堆栈使用准备好的语句。 Postgresql缓存 执行计划。下一次使用相同的语句时,postgresql会重用 执行计划。这可以节省DB中的时间计划语句。

此外,c3p0可以缓存“java.sql.PreparedStatement” 的java实例,这意味着它正在缓存java对象。所以当使用
c3p0.maxStatementsPerConnection = 100时,它会缓存至多100个不同的对象的
对象。它节省了创建对象的时间,但这与postgresql数据库及其准备的语句无关 。

,对吗?

当我们使用约100个不同的语句我会成立 c3p0.maxStatementsPerConnection = 100

但C3P0文档说在c3p0 known shortcomings

语句池的开销 太高。对于不支持 的驱动程序,执行 PreparedStatements的重要预处理,共用 开销超过了任何节省。 默认情况下,语句池关闭为 。如果您的驱动程序执行 预处理PreparedStatements, ,特别是如果它通过具有 RDBMS的IPC执行,您可能会看到 明显的性能增益, 将语句池合并。 (通过将配置属性 maxStatements或 maxStatementsPerConnection设置为大于零的值 来执行此操作 )。

所以:用c3p0和Postgresql激活maxStatementsPerConnection是否合理? 激活它有没有真正的好处?

亲切的问候 Janning

回答

23

我不记得的副手,如果Hibernate的实际存储的PreparedStatement实例本身,或依赖于连接提供商重用他们。(BatcherImpl的快速扫描表明,如果连续多次执行相同的SQL,它会重用最后一个PreparedStatement)

我认为c3p0文档试图做的一点是,对于许多JDBC驱动程序,PreparedStatement不是' t很有用:一些驱动程序最终只会在客户端拼接参数,然后将构建的SQL语句传递到数据库。对于这些驱动程序,PreparedStatements根本没有优势,任何重复使用的努力都是浪费的。 (Postgresql JDBC FAQ说这是在sever协议版本3之前的Postgresql的情况,并且在documentation中有更详细的信息)。

对于确实有效处理PreparedStatements的驱动程序,仍然可能需要实际重用PreparedStatement实例才能获得任何好处。例如,如果驱动程序实现:

  • 各种Connection.prepareStatement(SQL) - 创建一个服务器端的声明
  • PreparedStatement.execute(..)等等 - 执行服务器端声明
  • PreparedStatement.close () - 取消分配服务器端的声明

鉴于此,如果应用程序总是打开一个事先准备好的声明,执行一次,然后再次关闭它,有仍然没有好处;事实上,这可能会更糟,因为现在可能会有更多的往返行程。所以应用程序需要挂在PreparedStatement实例上。当然,这会导致另一个问题:如果应用程序挂起太多,并且每个服务器端语句都会消耗一些资源,那么这会导致服务器端问题。在有人直接使用JDBC的情况下,这可能需要手动管理 - 一些语句已知是可重用的,因此已准备就绪;有些不是,只是使用暂时的Statement实例。 (这是跳过预处理语句的其他好处:处理参数转义)

所以这就是为什么c3p0和其他连接池也准备好语句缓存 - 它允许应用程序代码避免处理所有这些。这些语句通常保存在一些有限的LRU池中,因此常用语句重用PreparedStatement实例。

这个难题的最后一部分是JDBC驱动程序可能自己决定要聪明并做到这一点;而且服务器本身也可能决定变得聪明,并检测到提交与前一个结构类似的语句的客户。

鉴于Hibernate本身并没有保留PreparedStatement实例的缓存,所以你需要让c3p0做到这一点,以获得它们的好处。 (由于重复使用缓存计划,这应该减少常见语句的开销)。如果c3p0没有缓存准备好的语句,那么驱动程序只会看到应用程序准备一个语句,执行它,然后再次关闭它。看起来JDBC驱动程序有一个"threshold" setting用于在应用程序始终执行此操作的情况下避免准备/执行服务器开销。所以,是的,你需要有c3p0做语句缓存。

希望有帮助,对不起有点冗长。答案是

+1

伟大的答案!有了你的详细解释,我可以进行一些测试。事实上:激活c3p0语句池是合理的。 之前,我的语句每次解析和计划,现在他们只能绑定和执行。 但请注意您的数据是否改变以及旧计划的执行效果不佳。我还不知道postgresql是否会不时重复准备好的语句。 非常感谢你的帮助! – Janning 2010-05-28 19:50:23

+0

很棒的回答!实际上,我总是对PreparedStatement的实现感到困惑,并且怀疑每个人都告诉我的好处。 – Chao 2016-07-31 18:06:16

2

记住语句具有每连接被缓存,这将意味着你将要消耗的内存相当一大块,而且需要很长一段时间之前,你会看到任何好处。因此,如果您将它设置为使用100条语句进行缓存,那实际上是100 *个连接数或100个/否连接,但您仍然需要花费相当长的时间,直到您的缓存具有任何有意义的效果。

相关问题