1

我在我的 Web 应用程序(没有 Spring)中结合使用 Hibernate 和 c3p0。一夜之间,我的数据库连接似乎超时(或至少其中一个),第二天我得到了一个损坏的管道异常。
以下是我用于该项目的配置。

    <hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/**********?autoReconnect=true</property>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
        <property name="hibernate.connection.username">********</property>
        <property name="hibernate.connection.password">********</property>
        <property name="hibernate.show_sql">false</property>
        <property name="hibernate.globally_quoted_identifiers">true</property>
        <property name="hibernate.current_session_context_class">thread</property>
        <property name="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
        <property name="hibernate.connection.autocommit">false</property>
        <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>

        <property name="hibernate.c3p0.min_size">5</property>
        <property name="hibernate.c3p0.max_size">25</property>
        <property name="hibernate.c3p0.timeout">300</property>
        <property name="hibernate.c3p0.max_statements">50</property>
        <property name="hibernate.c3p0.idle_test_period">60</property>
        <property name="hibernate.c3p0.acquire_increment">1</property>
        <property name="hibernate.c3p0.acquireRetryAttempts">5</property>
        <property name="hibernate.c3p0.acquireRetryDelay">250</property>
        <property name="hibernate.c3p0.preferredTestQuery">select 1;</property>
        <property name="hibernate.c3p0.validate">true</property>
        <property name="hibernate.c3p0.testConnectionOnCheckout">true</property>
        <property name="hibernate.c3p0.testConnectionOnCheckin">true</property>
    </session-factory>
</hibernate-configuration>

我得到的异常如下所示:

    从服务器成功接收到的最后一个数据包是 56,974,967 毫秒前。
    最后一个成功发送到服务器的数据包是 56,974,967 毫秒前。是
    长于服务器配置的“wait_timeout”值。你应该考虑
    在您的应用程序中使用之前过期和/或测试连接有效性,增加
    服务器为客户端超时配置值,或使用连接器/J 连接
    属性 'autoReconnect=true' 来避免这个问题。
    org.hibernate.exception.JDBCConnectionException:最后一个数据包成功接收
    来自服务器的时间是 56,974,967 毫秒前。最后一个数据包成功发送到
    服务器在 56,974,967 毫秒前。比服务器配置的值长
    'wait_timeout'。您应该考虑过期和/或测试连接
    在您的应用程序中使用之前的有效性,增加服务器配置的值
    客户端超时,或使用 Connector/J 连接属性 'autoReconnect=true'
    避免这个问题。

这里的问题是,我正在使用属性 autoReconnect=true,并且我正在测试连接有效性。(请参阅 c3p0 配置。)我相当确定 c3p0 配置已加载,因为以下内容显示在我的标准输出日志中:

    2014 年 4 月 8 日上午 10:57:13 com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource getPoolManager
    信息:初始化 c3p0 池... com.mchange.v2.c3p0.PoolBackedDataSource@f79fb235 [
    connectionPoolDataSource -> com.mchange.v2.c3p0.WrapperConnectionPoolDataSource@4e20d034 [
    acquireIncrement -> 1,acquireRetryAttempts -> 5,acquireRetryDelay -> 250,autoCommitOnClose ->
    假,自动测试表 -> 空,breakAfterAcquireFailure -> 假,checkoutTimeout -> 0,
    connectionCustomizerClassName -> null,connectionTesterClassName ->
    com.mchange.v2.c3p0.impl.DefaultConnectionTester,debugUnreturnedConnectionStackTraces -> false,
    factoryClassLocation -> null,forceIgnoreUnresolvedTransactions -> false,identityToken ->
    ph9ube91hyyxjw1mgbhpo|709689fb,idleConnectionTestPeriod -> 60,initialPoolSize -> 3,
    maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 300,
    maxIdleTimeExcessConnections -> 0, maxPoolSize -> 25, maxStatements -> 50, maxStatementsPerConnection
     -> 0,minPoolSize -> 5,nestedDataSource -> com.mchange.v2.c3p0.DriverManagerDataSource@a1ca3a3 [
    描述 -> null,driverClass -> null, factoryClassLocation -> null,identityToken ->
    ph9ube91hyyxjw1mgbhpo|24bbab7, jdbcUrl -> jdbc:mysql://localhost:3306/********?autoReconnect=true,
    属性 -> {user=******, password=******, autocommit=false} ], preferredTestQuery -> 选择 1;,
    propertyCycle -> 0, testConnectionOnCheckin -> true, testConnectionOnCheckout -> true,
    unreturnedConnectionTimeout -> 0,使用TraditionalReflectiveProxies -> false;用户覆盖:{}],
    dataSourceName -> null, factoryClassLocation -> null, identityToken -> ph9ube91hyyxjw1mgbhpo|fedb05d,
     numHelperThreads -> 3]

异常的损坏管道部分是这样的:

    引起:com.mysql.jdbc.exceptions.jdbc4.CommunicationsException:从服务器成功接收到的最后一个数据包是 56,974,967 毫秒前。最后一个成功发送到服务器的数据包是 56,974,967 毫秒前。比服务器配置的“wait_timeout”值长。您应该考虑在应用程序中使用之前使连接有效性过期和/或测试,增加客户端超时的服务器配置值,或使用连接器/J 连接属性“autoReconnect=true”来避免此问题。
        在 sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        在 sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
        在 sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        在 java.lang.reflect.Constructor.newInstance(Constructor.java:525)
        在 com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
        在 com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1116)
        在 com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3851)
        在 com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2471)
        在 com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2651)
        在 com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2683)
        在 com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2144)
        在 com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2310)
        在 com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeQuery(NewProxyPreparedStatement.java:76)
        在 sun.reflect.GeneratedMethodAccessor35.invoke(未知来源)
        在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        在 java.lang.reflect.Method.invoke(Method.java:601)
        在 org.hibernate.engine.jdbc.internal.proxy.AbstractStatementProxyHandler.continueInvocation(AbstractStatementProxyHandler.java:122)
        ... 23 更多
    引起:java.net.SocketException: Broken pipe
        在 java.net.SocketOutputStream.socketWrite0(本机方法)
        在 java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109)
        在 java.net.SocketOutputStream.write(SocketOutputStream.java:153)
        在 java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
        在 java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
        在 com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3832)
        ... 33 更多

根据我在互联网上找到的内容,我尝试了以下方法:

  • 将 autoReconnect=true 添加到连接 URL (请注意,尝试使用后连接仍然断开,因此似乎没有重新连接)
  • 将 testConnectionOnCheckout 和 testConnectionOnCheckin 添加到 c3p0 配置中
  • 将 idle_test_period 和 preferredTestQuery 添加到 c3p0 配置

似乎没有任何效果。有没有人知道可能导致此问题的原因?

4

1 回答 1

2

所以,一些零散的想法:

你的preferredTestQuery. 它应该是“SELECT 1”而不是“SELECT 1;”。我认为如果这是一个问题,您会看到有关它的异常(并且结帐都会失败),但值得尝试解决这个问题。

【你用的是什么版本的c3p0?如果您想危险地生活并且正在使用最新的 MySQL 驱动程序,请尝试使用最新的预发行版,目前为 c3p0-0.9.5-pre8,并且根本不要设置preferredTestQuery。最新版本支持 JDBC4 Connection.isValid() 进行测试。]

另一种可能性是您的应用程序偶尔会长时间保持连接打开(签出)。这不会完全是连接泄漏,因为最终应用程序会尝试针对连接执行语句。但是,如果您的应用程序这样做,您会看到您所看到的,因为 c3p0 在客户端使用时不会测试连接,因此它们可以闲置。(我不知道为什么 autoReconnect 没有帮助,除非您可能处于事务中间并且 autoReconnect 对此不起作用?)如果您想测试这种情况,您可以使用unreturnedConnectionTimeout(可选与debugUnreturnedConnectionStackTraces)强制关闭 too-long-checked-out Exception 并尝试诊断问题。

如果您只是想让问题消失(并且不太关心理解它),您也可以尝试设置 c3p0 的maxConnectionAge和/或maxIdleTime。如果将这些设置为较大的值,这些设置不会对性能产生有意义的影响。(可能需要 7200 秒,即两个小时,尽管超过 ~1800 秒就可以了。)这些设置(尤其是 maxConnectionAge)非常简单,除非麻烦的连接按照上述方法保持打开并从池中签出一段时间很长时间。[唯一可以从客户端关闭()签出连接的 c3p0 设置是unreturnedConnectionTimeout。]

祝你好运!

于 2014-04-09T12:55:04.797 回答