我们正在运行java6 / hibernate / c3p0 / postgresql堆栈。 我们的JDBC驱动程序是8.4-701.jdbc3
我对准备好的陈述有几个问题。我读过了 关于Prepared Statements
的优秀文件但我仍然有一个问题如何使用postgresql配置c3p0。
目前我们有
c3p0.maxStatements = 0
c3p0.maxStatementsPerConnection = 0
根据我的理解,准备好的语句和语句池是两回事:
我们的hibernate堆栈使用预处理语句。 Postgresql正在缓存 执行计划。下次使用相同的语句时,postgresql会重用 执行计划。这样可以节省DB内部的时间计划语句。
另外c3p0可以缓存“java.sql.PreparedStatement”的java实例
这意味着它正在缓存java对象。所以使用时
c3p0.maxStatementsPerConnection = 100它最多缓存100个不同的
对象。它节省了创建对象的时间,但这与此无关
postgresql数据库及其准备好的语句。
右?
当我们使用大约100个不同的语句时,我会设置 c3p0.maxStatementsPerConnection = 100
但是c3p0文档在c3p0 known shortcomings
中说Statement pooling的开销是 太高。对于没有的司机 执行重要的预处理 PreparedStatements,汇集 开销超过任何节省。 因此关闭语句池 默认情况下。如果你的司机 预处理PreparedStatements, 特别是如果它通过IPC使用 在RDBMS中,你可能会看到一个 显着的性能提升 转动声明池。 (做这个 通过设置配置属性 maxStatements或 maxStatementsPerConnection为一个值 大于零。)。
所以:用c3p0和Postgresql激活maxStatementsPerConnection是否合理? 激活它真的有益吗?
亲切的问候 Janning答案 0 :(得分:25)
我不记得Hibernate是否实际存储了PreparedStatement实例,或者依赖连接提供程序来重用它们。 (对BatcherImpl的快速扫描表明,如果连续多次执行相同的SQL,它会重用最后的PreparedStatement)
我认为c3p0文档试图提出的一点是,对于许多JDBC驱动程序,PreparedStatement没有用:一些驱动程序最终会简单地在客户端拼接参数,然后将构建的SQL语句传递给无论如何,数据库。对于这些驱动程序,PreparedStatements根本没有优势,任何重用它们的努力都被浪费了。 (Postgresql JDBC FAQ表示在服务器协议版本3之前Postgresql就是这种情况,documentation中有更详细的信息。)
对于有效处理PreparedStatements的驱动程序,仍然可能需要实际重用PreparedStatement实例以获得任何好处。例如,如果驱动程序实现:
鉴于此,如果应用程序始终打开预准备语句,执行一次然后再次关闭它,那么仍然没有任何好处;事实上,它可能会更糟,因为现在可能会有更多的往返旅程。因此,应用程序需要挂起到PreparedStatement实例。当然,这会导致另一个问题:如果应用程序挂起太多,并且每个服务器端语句都会消耗一些资源,那么这可能会导致服务器端问题。在有人直接使用JDBC的情况下,可以通过手工管理 - 一些已知的语句可以重用,因此可以准备;有些不是,只是使用瞬态Statement实例。 (这正在跳过准备语句的其他好处:处理参数转义)
所以这就是为什么c3p0和其他连接池也有预备语句缓存 - 它允许应用程序代码避免处理所有这些。这些语句通常保存在一些有限的LRU池中,因此常用语句重用PreparedStatement实例。
最后的难题是JDBC驱动程序可能自己决定聪明并且这样做;和服务器本身也可以决定聪明,并检测客户提交的结构与前一个相似的语句。
鉴于Hibernate本身并不保留PreparedStatement实例的缓存,您需要让c3p0这样做才能获得它们的好处。 (由于重用缓存计划,应减少常见语句的开销)。如果c3p0没有缓存预准备语句,那么驱动程序将只看到应用程序准备语句,执行它,然后再次关闭它。看起来JDBC驱动程序有一个"threshold" setting,用于在应用程序始终执行此操作时避免准备/执行服务器开销。所以,是的,你需要让c3p0进行语句缓存。
希望有所帮助,对不起它有点长啰嗦。答案是是。
答案 1 :(得分:2)
请记住,语句必须按连接进行缓存,这意味着您将不得不消耗相当多的内存,并且在您看到任何好处之前需要很长时间。因此,如果您将其设置为使用100个语句进行缓存,那实际上是100 *连接数,或者100 /无连接数,但您仍需要花费相当长的时间,直到缓存产生任何有意义的效果。