简体   繁体   English

使用@PostConstruct时,Hibernate无法找到绑定到线程的会话

[英]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. 我正在重做一个较旧的Spring项目,以更多地反映应该在Spring 3.0.x中完成的工作。

One of the changes I made was to the repository/dao layer. 我所做的更改之一是对存储库/ dao层。 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. 根据最佳实践的建议,我不再从HibernateDaoSupport扩展为使用HibernateTemplate ,而是直接通过使用sessionFactory.getCurrentSession()直接使用Hibernate SessionFactory ,该产品应该与Spring 3.0.x及更高版本一起使用。

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 . 对于整个项目来说,这是一个很大的福音,因为它摆脱了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) 但是,我刚刚注意到,我无法再调用使用@PostConstruct(或在XML应用程序上下文中使用bean的onStartUp属性)的Service方法。

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: 例如,使用HibernateTemplate可以正常使用此方法,但是现在Hibernate抛出异常,抱怨没有线程绑定会话:

@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. 我可以删除此@PostConstruct方法调用...这是系统中唯一的方法。 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>

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." HibernateDaoSupport类文档中所述 ,“如果传入SessionFactory,则此类将创建自己的HibernateTemplate实例。默认情况下,该HibernateTemplate上的'allowCreate'标志将为'true'。” That means that under the old system, your DAOs could open sessions on demand without being under any kind of real control. 这意味着在旧系统下,您的DAO可以按需打开会话,而无需任何实际控制。

When Spring is managing the SessionFactory, it installs a SpringSessionContext as Hibernate's CurrentSessionContext . 当Spring管理SessionFactory时,它将安装SpringSessionContext作为Hibernate的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. 现在,当您调用SessionFactory.getCurrentSession() ,SpringSessionContext在Spring管理的ThreadLocal中查找会话,如果不存在,则失败。 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. 在您的情况下,您不是在执行代码以响应请求,因此OSIV不在活动中,并且您显然也未处于活动事务中。 Making the method transactional will take care of your problem. 使该方法具有事务性将解决您的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM