Guille
Guille

Reputation: 2320

I don't get session for Hibernate in thread for an web application in Tomcat

I have an web application with Tomcat. I am using some Threads than execute in the Controller. Inside this Thread I execute others Threads.

This threads need to have a session with Hibernate , but it's not working when I execute some query, although I open a new session in the "run" method of each thread.

When I execute this code outsite of a Tomcat, it works, like a simple java main. So, it looks like it's something I do wrong with Tomcat. I guess it could be because the OpenSessionInViewFilter. I get an error about the current thread doesn't have a session.

The exception that I get is:

org.hibernate.HibernateException: No Session found for current thread
    at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
    at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:941)

My web.xml

<filter>
        <filter-name>sessionView</filter-name>
        <filter-class>
            org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>sessionView</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

My Controller

 @Override
    protected ModelAndView onSubmit(final HttpServletRequest request,
            final HttpServletResponse response, final Object command, final BindException errors)
            throws Exception {          
        MyThread thread = new ExecuteETLThread();
        thread.start();
        ...
    }

MyThread:

public final class MyThread extends AbstracThread {

 @Override
    public void runThread() {
        try {
            //I get an exception here. I just put this senstence here for checking.
            context.getConfigurationDAO().get("A");            
            //Normally, I open more threads here that they connect with hibernate and fail.
            //otherThread.start();
        } catch (final Exception e) {
            LOG.error(e);
        }
    }

AbstractThread:

public abstract class AbstractThread extends Thread {
    @Override
    public final void run() {
        try {
            OpenSessionInView.openSession();
            runThread();
        } catch (final Exception e) {
            LOG.error("Error running BidoopThread", e);
        } finally {
            OpenSessionInView.closeSession();
        }
    }
    public abstract void runThread();
}

To open the session with Hibernate.

public final class OpenSessionInView {
    public static void openSession() {
        final SessionFactory sf = Factory.getSessionFactory();

        final Session session = sf.openSession();
        session.setFlushMode(FlushMode.COMMIT);
        TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session));
    }

    public static void closeSession() {
        final SessionFactory sf = Factory.getSessionFactory();
        final SessionHolder sessionHolder =
                (SessionHolder) TransactionSynchronizationManager.unbindResource(sf);
        SessionFactoryUtils.closeSession(sessionHolder.getSession());
    }

Upvotes: 0

Views: 376

Answers (1)

Alexey Andreev
Alexey Andreev

Reputation: 2085

Both OpenSessionInViewFilter and spring's delegate for EntityManager use ThreadLocal to store real EntityManager implementation. And they bind an EntityManager to this ThreadLocal each time request being initiated, in a thread of this request. So EM won't be bound to the thread you create manually. You should observe your stack trace and figure out where does spring look for EM (or session). According to stack trace you provided, learn the SpringSessionContext to find a way to bind session manually. Also you need to perform some work to clean up session as thread completes.

Upvotes: 2

Related Questions