Erik
Erik

Reputation: 12140

How to deal with Background Threads in a Hibernate/Spring Application

I am asking me how I should deal with background threads performing database-involving tasks in my Hibernate/Spring web application.

Currently I am using the following interceptor, so I can annotate my thread run methods with @OpenSession and a session should be opened. This should also work for RMI requests for example or any other method that is called without a session being opened. However, I am not sure if the code is correct, I face the problem that sometimes the sessions are just not closed and kept open forever.

@Around("@annotation(openSession)")
    public Object processAround(ProceedingJoinPoint pjp, OpenSession openSession) throws Throwable {

        boolean boundResource = false;
        Session session = null;

        // Bind the session to the thread, if not already done
        if(TransactionSynchronizationManager.getResource(sessionFactory) == null) {
            log.debug("Opening Hibernate Session in method "+pjp.getSignature());

            session = SessionFactoryUtils.getSession(sessionFactory, true);
            TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
            boundResource = true;
        }

        // Invoke the annotated method
        Object ret;
        try {
            ret = pjp.proceed();
        }
        catch(Throwable t) {
            // Rethrows the Exception but makes sure the session will be closed
            SessionFactoryUtils.closeSession(session);
            log.debug("Closing Hibernate Session in method (Exception thrown) "+pjp.getSignature());
            throw t;
        }

        // If a resourc was bound by this method call, unbind it.
        if(boundResource) {
            //SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
            session.flush();
            SessionFactoryUtils.closeSession(session);

            log.debug("Closing Hibernate Session in method "+pjp.getSignature());
        }

        return ret;
    }

Upvotes: 3

Views: 2302

Answers (2)

hertzsprung
hertzsprung

Reputation: 9893

Yes, your suggested solution should work (I've done something very similar myself). If you only use @Transactional, you'll get a new EntityManager for each transaction, which isn't necessarily optimal if your background thread has many transactions.

Upvotes: 1

Olaf
Olaf

Reputation: 6289

Hibernate sessions and JDBC connections are not thread safe. You should stick with a connection and a session per thread.

Upvotes: 1

Related Questions