检查c3p0池中的连接

Rad*_*ski 5 java hibernate c3p0 socketexception

我正在使用Java SE应用程序开发,使用Hibernate 4和c3p0与MariaDB数据库进行通信.它是长时间运行的应用程序,等待来自外部的信号,因此有时数据库会在8小时不活动后关闭我的连接.我试图配置c3p0连接验证,但它不起作用.你可以帮帮我吗?

错误日志(在命名查询执行期间抛出):

2014-10-27 08:10:19.062 ERROR [trans] com.example.runnable.T1 - Exception thrown during event processing, rollbacking transaction: org.hibernate.exception.JDBCConnectionException: could not extract ResultSet
        at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:132)
        at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
        at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:126)
        at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:112)
        at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:91)
        at org.hibernate.loader.Loader.getResultSet(Loader.java:2065)
        at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1862)
        at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1838)
        at org.hibernate.loader.Loader.doQuery(Loader.java:909)
        at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:354)
        at org.hibernate.loader.Loader.doList(Loader.java:2553)
        at org.hibernate.loader.Loader.doList(Loader.java:2539)
        at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2369)
        at org.hibernate.loader.Loader.list(Loader.java:2364)
        at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:496)
        at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:387)
        at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:231)                                                                                                                                                    
        at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1264)                                                                                                                                                                    
        at org.hibernate.internal.QueryImpl.list(QueryImpl.java:103)                                                                                                                                                                         
        at com.example.runnable.T1.find(EventsTransmitter.java:140)                                                                                                                         
        at com.example.runnable.T1.run(EventsTransmitter.java:86)                                                                                                                                  
        at java.lang.Thread.run(Thread.java:745)                                                                                                                                                                                             
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 108,132,692 milliseconds ago.  The last packet sent successfully to the server was 108,132,692 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.                                                                                                                                                              
        at sun.reflect.GeneratedConstructorAccessor30.newInstance(Unknown Source)                                                                                                                                                            
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)                                                                                                                              
        at java.lang.reflect.Constructor.newInstance(Constructor.java:408)                                                                                                                                                                   
        at com.mysql.jdbc.Util.handleNewInstance(Util.java:377)                                                                                                                                                                              
        at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1036)                                                                                                                                                         
        at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3661)                                                                                                                                                                                    
        at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2417)                                                                                                                                                                             
        at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2582)                                                                                                                                                                          
        at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2530)                                                                                                                                                                   
        at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1907)                                                                                                                                                     
        at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2030)                                                                                                                                                        
        at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:82)                                                                                                                                       
        ... 17 more                                                                                                                                                                                                                          
Caused by: java.net.SocketException: Broken pipe                                                                                                                                                                                             
        at java.net.SocketOutputStream.socketWrite0(Native Method)                                                                                                                                                                           
        at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109)
        at java.net.SocketOutputStream.write(SocketOutputStream.java:153)
        at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
        at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
        at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3643)
        ... 23 more
Run Code Online (Sandbox Code Playgroud)

pom.xml中:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.33</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>4.3.6.Final</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.1.2.Final</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>4.3.1.Final</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-ehcache</artifactId>
    <version>4.3.6.Final</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-c3p0</artifactId>
    <version>4.3.6.Final</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

SRC /主/资源/ hibernate.cfg.xml中:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/MyBase?zeroDateTimeBehavior=convertToNull&amp;autoReconnect=true</property>
    <property name="hibernate.connection.username">user</property>
    <property name="hibernate.connection.password">pass</property>

    <property name="hibernate.current_session_context_class">thread</property>

    <property name="show_sql">true</property>
    <property name="use_sql_comments">true</property>

    <property name="hibernate.cache.use_second_level_cache">true</property>
    <property name="hibernate.cache.use_query_cache">true</property>
    <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>

    <property name="hibernate.c3p0.min_size">5</property>
    <property name="hibernate.c3p0.max_size">10</property>
    <property name="hibernate.c3p0.timeout">300</property>
    <property name="hibernate.c3p0.max_statements">30</property>

    <mapping class="com.example.domain.E" />
    </session-factory>
</hibernate-configuration>
Run Code Online (Sandbox Code Playgroud)

SRC /主/资源/ C3P0-config.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <default-config>
    <property name="preferredTestQuery">SELECT 1 FROM DUAL</property>
    <property name="testConnectionOnCheckin">true</property>
    <property name="idleConnectionTestPeriod">1800</property> <!-- 30 minutes -->
    </default-config>
</c3p0-config>
Run Code Online (Sandbox Code Playgroud)

编辑

在启动日志中我得到了c3p0配置(由Netbeans的Maven执行):

...
INFO: Initializing c3p0 pool... com.mchange.v2.c3p0.PoolBackedDataSource@81187ff9
[ connectionPoolDataSource -> com.mchange.v2.c3p0.WrapperConnectionPoolDataSource@e1820e10 [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000,
autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null,
connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, debugUnreturnedConnectionStackTraces -> false, factoryClassLocation -> null,
forceIgnoreUnresolvedTransactions -> false, identityToken -> z8kflt95n558v5xddgsj|2cf3d63b, idleConnectionTestPeriod -> 1800, initialPoolSize -> 5,
maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 300, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 10, maxStatements -> 30,
maxStatementsPerConnection -> 0, minPoolSize -> 5, nestedDataSource -> com.mchange.v2.c3p0.DriverManagerDataSource@2f0d7eae [ description -> null, driverClass -> null,
factoryClassLocation -> null, identityToken -> z8kflt95n558v5xddgsj|1e6a3214, jdbcUrl -> jdbc:mysql://localhost:3306/MyBase?zeroDateTimeBehavior=convertToNull&autoReconnect=true,
properties -> {user=******, password=******} ], preferredTestQuery -> SELECT 1 FROM DUAL, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0,
testConnectionOnCheckin -> true, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false; userOverrides: {} ],
dataSourceName -> null, factoryClassLocation -> null, identityToken -> z8kflt95n558v5xddgsj|7161d8d1, numHelperThreads -> 3 ]
...
Run Code Online (Sandbox Code Playgroud)

编辑2

执行maven-shade-plugin创建的jar时,我得到:

paź27,2014 10:56:22 PM org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator instantiateC3p0Provider WARN:遇到HHH000022:c3p0属性,但在类路径中找不到c3p0提供程序类; 这些属性将被忽略.paź27,2014 10:56:22 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl配置WARN:HHH000402:使用Hibernate内置连接池(不供生产使用!)paź27,201410:56: 22 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator

或当我试图org.hibernate.connection.C3P0ConnectionProvider在属性中指出时:

信息:HHH000130:实例化显式连接提供程序:org.hibernate.connection.C3P0ConnectionProvider初始SessionFactory创建failed.org.hibernate.service.spi.ServiceException:无法创建请求的服务[org.hibernate.engine.jdbc.connections.spi.ConnectionProvider来自com.example.App的com.example.App.run(App.java:31)的com.example.util.HibernateUtil.(HibernateUtil.java:27)中的线程"main"java.lang.ExceptionInInitializerError中的异常. main(App.java:25)
引起:org.hibernate.service.spi.ServiceException:无法创建请求的服务[org.hibernate.engine.jdbc.connections.spi.ConnectionProvider]

    at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:261)

    at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:225)

    at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:206)

    at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.buildJdbcConnectionAccess(JdbcServicesImpl.java:260)

    at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(JdbcServicesImpl.java:94)

    at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:111)

    at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:234)

    at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:206)

    at org.hibernate.cfg.Configuration.buildTypeRegistrations(Configuration.java:1885)

    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1843)

    at com.example.util.HibernateUtil.<clinit>(HibernateUtil.java:24)

    ... 2 more                                                                                                                                                                                                                Caused by: org.hibernate.HibernateException: Could not instantiate
Run Code Online (Sandbox Code Playgroud)

连接提供者[org.hibernate.connection.C3P0ConnectionProvider]

    at org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator.instantiateExplicitConnectionProvider(ConnectionProviderInitiator.java:197)

    at org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator.initiateService(ConnectionProviderInitiator.java:120)
    at org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator.initiateService(ConnectionProviderInitiator.java:55)
    at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:105)
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:251)
    ... 12 more Caused by: org.hibernate.boot.registry.selector.spi.StrategySelectionException:
Run Code Online (Sandbox Code Playgroud)

无法在org.hibernate.boot.registry.selector.internal.StrategySelectorImpl.selectStrategyImplementor(StrategySelectorImpl.java)中将名称[org.hibernate.connection.C3P0ConnectionProvider]解析为策略[org.hibernate.engine.jdbc.connections.spi.ConnectionProvider] :128)at org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator.instantiateExplicitConnectionProvider(ConnectionProviderInitiator.java:194)... 16更多

但是从Maven开始,一切都很好.不幸的是我需要这个从单罐工作.任何想法为什么org.hibernate.connection.C3P0ConnectionProvider无法在阴影jar中找到?

Rad*_*ski 6

好的,我设法解决了所有问题.这是灵魂.

首先,正如Steve Waldman所说,c3p0实际上并未初始化,但在Hibernate 4.3 hibernate.connection.provider_class参数中应该是:org.hibernate.c3p0.internal.C3P0ConnectionProvider.在文档中,您可以阅读:

使用C3P0连接池的连接提供程序.如果设置了hibernate.c3p0.*属性,Hibernate将默认使用它.

但在我看来,最好自己设置这个参数,如果你使用的是c3p0配置文件而不是hibernate.c3p0.*属性,则需要它.


第二个问题是通过SessionFactory.openSession()在线程开始时调用并稍后使用相同的会话对象来获取会话.我想在数据库连接断开后,在池中重新创建了一个新的,使用旧的会话导致使用旧的,断开的连接.因此,可能的解决方案是SessionFactory.openSession()在捕获连接错误或SessionFactory.getCurrentSession()在每次通信开始时使用后获取新会话.我决定使用第二个选项(在这种情况下,我的应用程序等待外部信号,有时几个小时,所以我在每个信号后获得当前会话).


我的最终配置:

hibernate.cfg.xml中:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/MyBase?zeroDateTimeBehavior=convertToNull&amp;autoReconnect=true</property>
    <property name="hibernate.connection.username">user</property>
    <property name="hibernate.connection.password">pass</property>
    <property name="hibernate.connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property>

    <property name="hibernate.current_session_context_class">thread</property>

    <property name="show_sql">true</property>
    <property name="use_sql_comments">true</property>

    <property name="hibernate.cache.use_second_level_cache">true</property>
    <property name="hibernate.cache.use_query_cache">true</property>
    <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
    </session-factory>
</hibernate-configuration>
Run Code Online (Sandbox Code Playgroud)

C3P0-config.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <default-config>
    <property name="initialPoolSize">5</property>
    <property name="minPoolSize">5</property>
    <property name="maxPoolSize">10</property>
    <property name="checkoutTimeout">3000</property>
    <property name="maxStatementsPerConnection">30</property>

    <property name="preferredTestQuery">SELECT 1 FROM DUAL</property>
    <property name="testConnectionOnCheckin">true</property>
    <property name="testConnectionOnCheckout">false</property>
    <property name="idleConnectionTestPeriod">300</property> <!-- 5 minutes -->
    </default-config>
</c3p0-config>
Run Code Online (Sandbox Code Playgroud)

有了这个c3p0配置:

  • 每隔5分钟不对连接执行任何查询,它将被测试,因此它永远不会被DB无效(在标准配置中,MySQL在8小时不活动后使连接无效),
  • 如果DB将重新启动或连接将被手动终止,我们有两个选项:a)最多5分钟后将重新建立连接,b)如果应用程序尝试执行查询,HibernateException则会抛出自动连接重新建立,然后连接将是重新建立,下一个查询将成功.

可选择testConnectionOnCheckout设置为true以防止异常,但这会导致性能问题(请参阅文档).