1

I am using both Hibernate and C3P0 in version 4.3.1.Final. MySQL 5.6.14 (InnoDB for all tables).

C3P0 settings in hibernate.cfg.xml are:

<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<property name="hibernate.c3p0.timeout">300</property>
<property name="hibernate.c3p0.idle_test_period">3000</property>
<property name="hibernate.c3p0.preferredTestQuery">SELECT 1</property>
<property name="hibernate.c3p0.minPoolSize">3</property>
<property name="hibernate.c3p0.maxPoolSize">100</property>

When I commit a transaction for example:

public void editCategory(int id, String title) {
    Transaction tx = getTransaction();
    Query q = session.createQuery("FROM Category WHERE id = :id");
    q.setInteger("id", id);
    Category cat = (Category) q.uniqueResult();
    cat.setTitle(title);
    tx.commit();
}
private Transaction getTransaction() {
    Transaction tx = session.getTransaction();
    if (!tx.isActive()) {
        tx.begin();
    }
    return tx;
}

In approximately 3 of 5 attempts commit fails because of:

SEVERE: Servlet.service() for servlet [appserver.services.ApplicationConfig] in context with path [/AppServer] threw exception [org.hibernate.TransactionException: commit failed] with root cause
java.lang.NullPointerException
    at com.mchange.v2.c3p0.impl.NewProxyConnection.commit(NewProxyConnection.java:1284)
    at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doCommit(JdbcTransaction.java:112)
    at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:180)
    at appserver.dao.CategoryDao.createCategory(CategoryDao.java:60)
    at appserver.services.CategoryResource.createCategory(CategoryResource.java:41)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:151)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:171)
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$TypeOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:195)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:104)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:402)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:349)
    ... stacktrace continues

Is there something with C3P0 settings that I'm missing? Thanks for help!

kamelot
  • 491
  • 1
  • 7
  • 19

1 Answers1

2

Your app server is reporting the root cause of the root cause, that is it is skipping an Exception that would have reported the more informative message, "You can't operate on a closed Connection!!!"

You have a race condition in your application. The Object 'session' referenced in the methods you excerpt is very likely sometimes close()ed between the query and the commit. (The hibernate Session wraps the JDBC Connection.)

You need to understand the lifecycle of your Sessions, and ensure that this never happens. Most simply, you might avoid caching the Sessions at all. You would acquire them when needed, and close them immediately after use, that is after you've commit()ed your transaction (reliably, via a finally block or try-with-resources construct).

Steve Waldman
  • 13,689
  • 1
  • 35
  • 45
  • Steve, thank you for answer. I have static session factory and then in constructor of DAO object I initialize field session as following: this.session = HibernateUtil.getSessionFactory().getCurrentSession(); – kamelot Feb 19 '14 at 16:53
  • and I have session context class property set as: thread – kamelot Feb 19 '14 at 17:01
  • So, regarding the current Session, that under your config gets associated with a Thread: who opens it, and who close()es it? That is, as I understand it (and I'm no Hibernate expert!), SessionFactory.getCurrentSession() is a convenience that will acquire a Session that you have opened already [with SessionFactory.openSession()], which has been bound to a context [in your case a Thread], so you don't have to explicitly pass it around as a method argument. But you still have to openSession()s, understand their lifecycle, and very importantly from c3p0's perspective, close() them. – Steve Waldman Feb 19 '14 at 17:18
  • Be careful not to share Sessions in ways that you don't intend. That is, if you open a Session and it is bound to a Thread as its default context, it should still just be used during the course of one logical request or unit of work (which may involve a series of database transactions) and then closed. Sessions should be allowed to attach themselves to whatever Threads your appserver is using and then reacquired from those Threads whenever they happen to be handling a request. – Steve Waldman Feb 19 '14 at 17:23
  • I also understand it that current session should be associated with Thread who opens it. Since Session isn't AutoCloseable, try-with-resources can't be used, but it seems that opening and closing of Session after each transaction works: Session session = HibernateUtil.getSessionFactory().openSession(); try { Transaction tx = session.beginTransaction(); // do queries tx.commit(); } finally { session.close(); }. Thank you Steve! – kamelot Feb 19 '14 at 17:27
  • See e.g. http://stackoverflow.com/questions/8046662/hibernate-opensession-vs-getcurrentsession https://forums.hibernate.org/viewtopic.php?p=2384980 – Steve Waldman Feb 19 '14 at 17:34
  • (sorry! that comment with links was from the previous series; i just forgot to post it after Stack Exchange made me wait. i'm glad it's worked out! i like the clear try/finally approach, from c3p0's perspective that's the best, Connections get properly closed when they should.) – Steve Waldman Feb 19 '14 at 17:35