How to re-deploy a hibernate-c3p0 project on tomca

2020-07-26 07:33发布

问题:

If the project is re-deployed through netbeans on tomcat 7 then I get errors like

java.lang.IllegalStateException
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1600)
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1559)
    at com.mchange.v2.resourcepool.BasicResourcePool.checkIdleResources(BasicResourcePool.java:1481)
    at com.mchange.v2.resourcepool.BasicResourcePool.access$2000(BasicResourcePool.java:32)
    at com.mchange.v2.resourcepool.BasicResourcePool$CheckIdleResourcesTask.run(BasicResourcePool.java:1964)
    at java.util.TimerThread.mainLoop(Timer.java:512)
    at java.util.TimerThread.run(Timer.java:462)
Exception in thread "Timer-5" java.lang.NoClassDefFoundError: com/mchange/v2/resourcepool/BasicResourcePool$AsyncTestIdleResourceTask
    at com.mchange.v2.resourcepool.BasicResourcePool.checkIdleResources(BasicResourcePool.java:1481)
    at com.mchange.v2.resourcepool.BasicResourcePool.access$2000(BasicResourcePool.java:32)
    at com.mchange.v2.resourcepool.BasicResourcePool$CheckIdleResourcesTask.run(BasicResourcePool.java:1964)
    at java.util.TimerThread.mainLoop(Timer.java:512)
    at java.util.TimerThread.run(Timer.java:462)
Caused by: java.lang.ClassNotFoundException: com.mchange.v2.resourcepool.BasicResourcePool$AsyncTestIdleResourceTask
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1714)
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1559)
    ... 5 more

Today we got another strange error when we tried to re-deploy the project on tomcat 7

[5:07:02 PM] Nitin - Webscraper/Tester,Java/PHP developer: java.lang.NoClassDefFoundError: com/mchange/v2/lang/VersionUtils
 com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:104)
 com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:65)
 com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:62)
 com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:531)
 com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:128)
 org.hibernate.connection.C3P0ConnectionProvider.getConnection(C3P0ConnectionProvider.java:78)
 org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:446)
 org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:167)
 org.hibernate.jdbc.AbstractBatcher.prepareQueryStatement(AbstractBatcher.java:161)
 org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1700)
 org.hibernate.loader.Loader.doQuery(Loader.java:801)
 org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:274)
 org.hibernate.loader.Loader.doList(Loader.java:2542)
 org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2276)
 org.hibernate.loader.Loader.list(Loader.java:2271)

We have been getting such strange errors since quite some time now. When we try to debug, we find the classes already existing.

What I can think of is dangling c3p0 connection-pooling threads, which are either not destroyed properly on re-deploying, or may be having some active-connection executing or something similar.

Are there any best practices on how to re-deploy such a project which uses hibernate & c3p0 ? Is there some code that I have to write on contextDestroyed for proper closing of c3p0 threads ?

回答1:

I was also facing the same problem and I could see the below warning in my tomcat console

Jul 30, 2014 3:20:16 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads WARNING: The web application [/rmlcrm] appears to have started a thread named [C3P0PooledConnectionPoolManager[identityToken->1hge50p9311d8syo1hfjimz|19ddf1db]-HelperThread-#0] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread: java.lang.Object.wait(Native Method) com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:635)

I was reading a lot to find out a solution to this and came across the post Hibernate :OutOfMemoryError: PermGen space

One of the comment in the post by Nicholas Hemley suggested to add a custom ServletContextListener and explicitly close the C3P0 connections in contextDestroyed() method of the listener which will be executed when the application is un-deployed.

We did not use the code exactly as we did not want to hard-couple with C3P0. But we realized that we are not closing hibernate sessionFactory anywhere in our application. We added the code to close the hibernate session factory in contextDestroyed() of the ServletContextListener. Now we do not have the error and neither we get a warning in the tomcat console.

You may also want to read Hibernate : closing the session factory does not close the c3p0 connection pool



回答2:

a few thoughts:

1) if you have set up your hibernate app's lifecycle to map to your web-app's lifecycle (definitely true if hibernate and c3p0 libs live in your web-app's lib directory, potentially true even if not), you absolutely do need to make sure that c3p0 pools are destroyed prior to application recycle, often meaning a contextDestroyed method. in hibernate-speak, it is the SessionFactory that wraps the Connection pool; make sure that your application's SessionFactory is close()ed when your app shuts down on hot redeploy. there should be a symmetry: either in contextInitialized or lazily upon a first request, your SessionFactory should be initialized. it should be destroyed on application shutdown.

2) the latest (still pre-release) version of c3p0 has some settings designed to reduce the likelihood of contamination between c3p0 Threads and objects derived from expired web-app ClassLoaders, especially if c3p0 is loaded by a non web-app specific ClassLoader (e.g. if c3p0 libs live in $CATALINA_HOME/lib rather than in a webapp lib directory). if you are willing to upgrade to a prerelease [latest now is c3p0-0.9.5-pre5], then try the following new config settings:

 c3p0.privilegeSpawnedThreads=true
 c3p0.contextClassLoaderSource=library

hope this helps!