5

I'm working on a web application. Usually at the beginning of a request (through the architecture code), a Hibernate session is opened to work with DB transactions. At the end of the request the session is closed. This works great for all of our transactions, except that in one particular instance, I want to fire a thread from a request. This thread will call DB transactions.

From the thread, I call "sessionFactory.openSession()", and with this session I perform my transactions. The problem arises in that when the request finishes, the thread itself may not necessarily be finished. So when the request finishes and the thread tries to perform another DB transaction I get a Hibernate Session is Closed! error.

Is there anyway that from my thread, I can open a "clean" session, not associated to the one opened at the start of the request?

Jaime Garcia
  • 6,744
  • 7
  • 49
  • 61
  • To clarify, is `openSession()` being called from the request thread, or the spawned thread? – skaffman Feb 25 '10 at 21:04
  • openSession is first being called from the request (the servlet), and then again from the spawned thread. – Jaime Garcia Feb 25 '10 at 21:05
  • 1
    shouldn't sessionFactory.openSession() give you a "clean" session that isn't associated with the one opened at the start of the request? are you sure your thread is called openSession and not getCurrentSession? – stmax Feb 25 '10 at 21:16
  • That's what I figured, and yes it is calling openSession(). If openSession() is giving a new session, then how is it that the spawned thread's session is dying somewhere in the middle of the transactions? – Jaime Garcia Feb 25 '10 at 21:24

2 Answers2

1

You can create an threading service, which extends HibernateAccessor, as a standalone Spring service, defined at spring.xml, and send to it code/data you want to process. Something like this:

    Session session = SessionFactoryUtils.getSession(
            getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());
    SessionHolder sessionHolder = null;
    try {
        applyFlushMode(session, false);
        sessionHolder = new SessionHolder(session);
        TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
        Transaction t = getSessionFactory().getCurrentSession().beginTransaction();
        try {

            //execute your code here

            t.commit();
        } catch (Exception e) {
            t.rollback();
            log.error("Error", e);
        }
        try {
            flushIfNecessary(sessionHolder.getSession(), false);
        }
        catch (HibernateException ex) {
            throw convertHibernateAccessException(ex);
        }
    } finally {
        SessionFactoryUtils.closeSession(sessionHolder.getSession());
        TransactionSynchronizationManager.unbindResource(getSessionFactory());
    }
Igor Artamonov
  • 35,450
  • 10
  • 82
  • 113
0

You can use JPA Entity Manager to begin and commit transactions manually. Here is my extended answer

adlerer
  • 1,010
  • 11
  • 14