我正在将hibernate 3与c3p0一起用于一个程序,该程序不断从某些源中提取数据并将其写入数据库。 现在问题是,由于某些原因,数据库可能变得不可用(在最简单的情况下:我只是将其关闭)。
如果要将任何内容写入数据库,则不应该有任何异常 - 查询应该等待所有永恒,直到数据库再次可用。 如果我没有弄错,这是连接池可以为我做的事情之一:如果db存在问题,只需重试连接 - 在最坏的情况下为无穷大。
但相反,我得到一个破坏的管道异常,有时后面的连接被拒绝,然后异常被传递给我自己的代码,这不应该发生。
即使我发现异常,我怎么能再次干净地重新初始化休眠? (到目前为止没有c3p0我只是简单地建立了会话工厂,但如果可以泄漏连接(或者可以这样做,我不会感到惊讶吗?))。
数据库是Virtuoso开源版。
我的hibernate.xml.cfg c3p0 config:
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<property name="hibernate.c3p0.breakAfterAcquireFailure">false</property>
<property name="hibernate.c3p0.acquireRetryAttempts">-1</property>
<property name="hibernate.c3p0.acquireRetryDelay">30000</property>
<property name="hibernate.c3p0.automaticTestTable">my_test_table</property>
<property name="hibernate.c3p0.initialPoolSize">3</property>
<property name="hibernate.c3p0.minPoolSize">3</property>
<property name="hibernate.c3p0.maxPoolSize">10</property>
顺便说一下:测试表已经创建,我得到了大量的调试输出 - 所以看起来它实际上是在读取配置。
答案 0 :(得分:3)
你错了。连接池只是一个连接池,它包含一些已建立的数据库物理连接,用于避免在需要其中一个连接时创建这些连接的开销。如果我没有弄错,这是连接池可以为我做的事情之一:如果db存在问题,只需重试连接 - 在最坏的情况下为无穷大。
也就是说,这些连接可能会变得陈旧(例如,如果重新启动数据库)。幸运的是,大多数连接池都可以配置为测试连接是否仍然有效,并在分发之前更新它们。 c3p0支持Configuring Connection Testing中记录的此功能,您实际上已经使用了各种选项之一。因此,当数据库恢复时,应该更新您的连接。
但是,当数据库出现故障时,不要指望您的应用程序被神奇地暂停,池不会这样做。
答案 1 :(得分:1)
看来BoneCP实际上已经实现了这一点。它可以设置为记录事务并在网络或数据库故障时重放它:
答案 2 :(得分:0)
谢谢你的回答。 我似乎还没有真正理解该部分的最后一段 http://www.mchange.com/projects/c3p0/index.html#configuring_recovery
因为起初似乎c3p0可以做到这一点(检测过时的连接并重试获取所有永恒的连接而不抛出应用程序代码的异常(当然除非它的错误与sql语句相关而不是连接),但在最后一段 - 以相当混乱的方式写 - 似乎c3p0无法确保100%。
所以我的解决方案是从jdbc Connection接口为我需要的方法创建一个小包装器,如果查询因连接错误而失败,它会尝试重新连接。当然它有点hacky,因为我宁愿我的组件使用标准的Connection接口而不是我自己的接口,但至少它现在干净利落。
答案 3 :(得分:0)
你忘记了:
因此,您的申请必须重新启动交易。我能想到的唯一可能的方法是让连接池跟踪对连接句柄的每次调用,并在出现错误时重播这些调用,但这会大大减慢连接池的速度。
对于BoneCP(http://jolbox.com),池通过首先捕获JDBC驱动程序抛出的异常并通过将该连接标记为错误或通过重新创建整个连接来处理它来检测到发生了故障池。
编辑:现在正在处理。