egervari
egervari

Reputation: 22512

Hibernate cannot find session bound to thread when using @PostConstruct

I'm reworking an older Spring project to more reflect how things are supposed to be done in Spring 3.0.x.

One of the changes I made was to the repository/dao layer. As advised by best practices, I no longer extend from HibernateDaoSupport to use the HibernateTemplate, but instead I use the Hibernate SessionFactory directly by using sessionFactory.getCurrentSession(), which is supposed to work with Spring 3.0.x and above.

This has been a very big boon for the project as a whole, as it gets rid of all of the wrapping code caused by HibernateTemplate. However, I just noticed that I can no longer call into Service methods that were using @PostConstruct (or were using the bean's onStartUp attribute in the XML application context)

For example, this method used to work just fine using HibernateTemplate, but now Hibernate throws an exception complaining that there is no session bound to the thread:

@Override
@PostConstruct
public void onStartUp() {
    logger.debug("Starting Bootstrap Service...");

    createSysAdminUser();
    createDefaultRoles();
    createDefaultThemes();

    createStopListIfDoesNotExist();
    stopListService.load();

    partialMappingService.load();
    dictionaryService.load();
}

I could just remove this @PostConstruct method call... it's the only one in the system. It is called when the application starts up to bootstrap data for a new application. Most of the time, it does nothing on a production system, but it's handy to have it for test and development databases that were created fresh.

Any ideas as to why and how I can fix it?

Thanks!

EDIT: Here is my transaction manage advice config:

<aop:config>
    <aop:advisor advice-ref="transactionAdvice"
                 pointcut="execution(* *..service.*.*(..))" order="1"/>
    <!-- gets sub packages like service.user -->
    <aop:advisor advice-ref="transactionAdvice"
                 pointcut="execution(* *..service.*.*.*(..))" order="2"/>
</aop:config>

<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="find*" read-only="true" propagation="REQUIRED"/>
        <tx:method name="get*" read-only="true" propagation="REQUIRED"/>
        <tx:method name="*" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>

Upvotes: 1

Views: 1227

Answers (1)

Ryan Stewart
Ryan Stewart

Reputation: 128829

As outlined in the HibernateDaoSupport class docs, "This class will create its own HibernateTemplate instance if a SessionFactory is passed in. The 'allowCreate' flag on that HibernateTemplate will be 'true' by default." That means that under the old system, your DAOs could open sessions on demand without being under any kind of real control.

When Spring is managing the SessionFactory, it installs a SpringSessionContext as Hibernate's CurrentSessionContext. Now when you call SessionFactory.getCurrentSession(), the SpringSessionContext looks in a Spring-managed ThreadLocal for a Session and fails if it's not there. A Session is typically opened and placed there in one of two ways: using the open-session-in-view pattern does it upon each new request, and starting a transaction does so, too. In your case, you're not executing code in response to a request, so OSIV isn't in play, and you apparently aren't in an active transaction, either. Making the method transactional will take care of your problem.

Upvotes: 1

Related Questions