2013-05-23 13 views
6

MySQLを使用するTomcatアプリケーションとORM用のHibernateがあります。アプリケーションの性質上、NoSQLストアから多数の解析データを取得して集約する必要があるため、各要求の引き出しと集約をいくつかのタスクに分割し、それらをスレッドプールエグゼキュータサービスに委任します。Hibernate/MySQL接続タイムアウト - スレッドプールされたエグゼキュータを処理して、終了後にC3P0へのHibernate接続を解放しようとしていません。

各スレッドがタスクを実行するとき、それは(私たちは、接続プーリングに使用)C3P0からのHibernateセッションを借りて、特定の物事について/更新MySQLを照会する必要があります。

エッセンシャル設定:

<property name="current_session_context_class">thread</property> 
    <property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property> 
    <property name="hibernate.connection.shutdown">true</property> 
    <property name="hibernate.use_sql_comments">false</property> 

<!-- C3p0 Performance Improvements --> 
    <property name="hibernate.c3p0.acquire_increment">1</property> 
    <property name="hibernate.c3p0.idle_test_period">300</property> 
    <property name="hibernate.c3p0.maxConnectionAge">3600</property> 
    <property name="hibernate.c3p0.timeout">120</property> 
    <property name="hibernate.c3p0.max_size">300</property> 
    <property name="hibernate.c3p0.min_size">1</property> 
    <property name="hibernate.c3p0.max_statements">100</property> 
    <property name="hibernate.c3p0.preferredTestQuery">select 1;</property> 

問題はHibernateの要求が8時間後のMySQL/JDBC接続タイムアウトエラーが発生している(MySQLのWAIT_TIMEOUTパラメータの私達の設定した値は、デフォルトすなわち8時間です)。私は11分にWAIT_TIMEOUTを設定することで、これを複製したが、結果はWAIT_TIMEOUTにも8時間で同じです:

2013-01-27 20:08:00,088 ERROR [Thread-0] (JDBCExceptionReporter.java:234) - Communications link failure 

The last packet successfully received from the server was 665,943 milliseconds ago. The last packet sent successfully to the server was 6 milliseconds ago. 
org.hibernate.exception.JDBCConnectionException: could not execute query 
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:99) 
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66) 
    at org.hibernate.loader.Loader.doList(Loader.java:2536) 
    at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2276) 
    at org.hibernate.loader.Loader.list(Loader.java:2271) 
    at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:119) 
    at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1716) 
    at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:347) 
    ..... 
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure 
The last packet successfully received from the server was 665,943 milliseconds ago. The last packet sent successfully to the server was 6 milliseconds ago. 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source) 
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) 
    at java.lang.reflect.Constructor.newInstance(Unknown Source) 
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:411) 
    at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1116) 
    at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3102) 
    at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:2991) 
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3532) 
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2002) 
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2163) 
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2624) 
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2127) 
    at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2293) 
    at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeQuery(NewProxyPreparedStatement.java:76) 
    at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208) 
    at org.hibernate.loader.Loader.getResultSet(Loader.java:1953) 
    at org.hibernate.loader.Loader.doQuery(Loader.java:802) 
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:274) 
    at org.hibernate.loader.Loader.doList(Loader.java:2533) 
    ... 9 more 
Caused by: java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost. 
    at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:2552) 
    at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3002) 
    ... 22 more 

2013-01-27 20:19:00,179 WARN [Thread-0] (NewPooledConnection.java:487) - [c3p0] Another error has occurred [ com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 1,326,037 milliseconds ago. The last packet sent successfully to the server was 660,100 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. ] which will not be reported to listeners! 
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 1,326,037 milliseconds ago. The last packet sent successfully to the server was 660,100 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.NativeConstructorAccessorImpl.newInstance0(Native Method) 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source) 
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) 
    at java.lang.reflect.Constructor.newInstance(Unknown Source) 
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:411) 
    at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1116) 
    at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3364) 
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1983) 
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2163) 
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2624) 
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2127) 
    at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2293) 
    at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeQuery(NewProxyPreparedStatement.java:76) 
    at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208) 
    at org.hibernate.loader.Loader.getResultSet(Loader.java:1953) 
    at org.hibernate.loader.Loader.doQuery(Loader.java:802) 
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:274) 
    at org.hibernate.loader.Loader.doList(Loader.java:2533) 
    at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2276) 
    at org.hibernate.loader.Loader.list(Loader.java:2271) 
    at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:119) 
    at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1716) 
    at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:347) 
    .... 
Caused by: java.net.SocketException: Broken pipe 
    at java.net.SocketOutputStream.socketWrite0(Native Method) 
    at java.net.SocketOutputStream.socketWrite(Unknown Source) 
    at java.net.SocketOutputStream.write(Unknown Source) 
    at java.io.BufferedOutputStream.flushBuffer(Unknown Source) 
    at java.io.BufferedOutputStream.flush(Unknown Source) 
    at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3345) 
    ... 20 more 

私は高負荷時に接続するようにC3P0が、頻繁に十分に失効した接続を立ち退かないと思いましたプールに戻され、失効し、退去する前に再び借りる。だから、私はc3p0.propertiesファイルを作成し、 "c3p0.testConnectionsOnCheckout"をtrueに設定して、失効した接続をプールから借りないようにしました。もう一度同じエラーが出ます。

私の休止状態のセッションはセッションコンテキスト「スレッド」で構成されているため、スレッドが使用するセッションはトランザクションがコミットまたはロールバックされるまで解放されないことがわかりました[http://docs.jboss.org/hibernate/orm/3.6/javadocs/org/hibernate/context/ThreadLocalSessionContext.html]。だから私が持っている唯一の説明は、エグゼキュータスレッドがコミットすることなく、読み取り専用のDB呼び出しを行い、タスクが完了すると、スレッドはセッションを保持してプールに戻ります。

ここで何をすればよいですか?私たちのアプリケーションは、Beanの種類ごとに1つずつ、Data-Access-Objectクラス内でコードをハイバネートします。私は、読み込み専用のDB呼び出しを行うクラス内のすべてのメソッドをそれぞれ不必要に「コミット」するように変更する必要はありません。私はまた、私たちのアプリのビジネスロジックへの変更を最小限に抑えたいと思っています。

Data-Access-Objectが宣言された/使用されるたびにsessionFactory.getCurrentSession()によって返されるセッションの新鮮度をチェックする方法はありますか?(すべてのData-Access-Objectクラスは単一の基底クラスなので、その基底クラスのコンストラクタ内のものを変更することができます)、プールに古くなったセッションを返す可能性がありますか?それとももっと良い方法がありますか?

ありがとうございました。

答えて

0

注:以下のOracleの例に基づいていますが、MySQL用に変更することができます。

私はTomcatの管理データベース化接続を使用することにより、切断された接続のこの問題を回避得ています。これは、このような何かを、あなたのMETA-INFディレクトリにあるcontext.xmlファイルを作成することによって行うことができます。

<Context crossContext="true" docBase="myBase" path="/myBase" reloadable="false" useHttpOnly="true"> 
    <ResourceLink global="jdbc/dbOne" name="jdbc/dbOne" type="javax.sql.DataSource" /> 
    <!-- Need another DB? --> 
    <!-- <ResourceLink global="jdbc/dbTwo" name="jdbc/dbTwo" type="javax.sql.DataSource" /> --> 
</Context> 

あなたのTomcatのserver.xmlファイルも更新する必要があります接続を作成するには。以下の私のhibernate.cfgで次に

<!-- Global JNDI resources 
    Documentation at /docs/jndi-resources-howto.html 
--> 
<GlobalNamingResources> 
<!-- Editable user database that can also be used by 
    UserDatabaseRealm to authenticate users 
--> 
<Resource name="UserDatabase" auth="Container" 
      type="org.apache.catalina.UserDatabase" 
      description="User database that can be updated and saved" 
      factory="org.apache.catalina.users.MemoryUserDatabaseFactory" 
      pathname="conf/tomcat-users.xml" /> 

    <!-- START MY MODS --> 
    <!-- Add the db connection(s)! The rest is standard in the server.xml file.-->   
    <Resource auth="Container" driverClassName="oracle.jdbc.driver.OracleDriver" initialSize="2" logAbandoned="true" maxActive="5" maxIdle="2" maxWait="120000" minEvictableIdleTimeMillis="1800000" minIdle="1" name="jdbc/dbOne" numTestsPerEvictionRun="3" password="openPlease" removeAbandoned="true" removeAbandonedTimeout="60" testOnBorrow="true" testOnReturn="true" testWhileIdle="true" timeBetweenEvictionRunsMillis="900000" type="javax.sql.DataSource" url="jdbc:oracle:thin:@servername:portnumber:schema" username="myUser" validationQuery="select sysdate from dual"/> 
    <!-- Need another connection? Copy and past the above making the required changes. --> 
    <!-- END MY MODS --> 

のTomcat 6.0.26に基づいています。xmlファイル私が指定されている:

<!-- Connection handling --> 
<property name="connection.datasource">java:/comp/env/jdbc/dbOne</property> 
<property name="dialect">org.hibernate.dialect.Oracle10gDialect</property> 
<property name="connection.autoReconnect">true</property> 
<property name="connection.autoReconnectForPools">true</property> 
<property name="connection.is-connection-validation-required">true</property> 
<property name="current_session_context_class">thread</property> 

だけC3P0を使用して、以下の設定が同様に私のために働いたが、彼らは私のTomcatサーバ上のアプリケーション間で共有することができるように私は今、Tomcatが接続を管理好む、これ、と述べました私の場合は望ましいです。

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE hibernate-configuration PUBLIC 
     "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 
     "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> 
<hibernate-configuration> 
    <session-factory> 
     <property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property> 
     <property name="hibernate.connection.password">@[email protected]</property> 
     <property name="hibernate.connection.url">@[email protected]</property> 
     <property name="hibernate.connection.username">someUser</property> 
     <property name="dialect">org.hibernate.dialect.Oracle10gDialect</property> 

     <property name="show_sql">false</property> 
     <property name="format_sql">false</property> 
     <property name="current_session_context_class">thread</property> 

     <!-- Connection handling --> 
     <property name="connection.autoReconnect">true</property> 
     <property name="connection.autoReconnectForPools">true</property> 
     <property name="connection.is-connection-validation-required">true</property> 
     <property name="current_session_context_class">thread</property> 
     <property name="max_fetch_depth">1</property> 

     <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">3000</property> 
     <property name="hibernate.c3p0.automaticTestTable">C3P0_TEST</property> <!-- c3p0 uses this table for testing connection. --> 
     <property name="hibernate.c3p0.initialPoolSize">2</property> <!-- 3 is c3p0 default. --> 
     <property name="hibernate.c3p0.minPoolSize">2</property> <!-- 1 is Hibernate default. --> 
     <property name="hibernate.c3p0.maxPoolSize">6</property> <!-- 100 is Hibernate default. --> 
     <property name="hibernate.c3p0.acquireIncrement">2</property> <!-- 3 is c3p0 default. --> 
     <property name="hibernate.c3p0.maxIdleTimeExcessConnections">600</property> <!-- 0 seconds is c3p0 default and means do not check. This is the num of seconds a connections in excess of minPoolSize are permitted to remain idle in the pool before being culled. --> 
     <property name="hibernate.c3p0.idleConnectionTestPeriod">30</property> <!-- 0 seconds is the c3p0 default and means do not check. (i.e. never test). Using only this provides the best performance even if individuals may occasionally receive an error message due to a connection being dropped. --> 

     <!-- Cache setup --> 
     <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">net.sf.ehcache.hibernate.EhCacheRegionFactory</property> 
     <!-- <property name="hibernate.cache.provider_class">net.sf.ehcache.hibernate.SingletonEhCacheProvider</property> --> 

     <property name="cache.use_minimal_puts">true</property> 
     <property name="hibernate.generate_statistics">true</property> 
     <property name="hibernate.cache.use_structured_entries">true</property> 

     <!-- Mapping files --> 
     ... 

     </session-factory> 

</hibernate-configuration> 
関連する問題