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

时间:2013-02-19 03:26:42

标签: java spring hibernate session postconstruct

我正在重新设计一个较旧的Spring项目,以更好地反映在Spring 3.0.x中应该如何完成的事情。

我做的一个更改是存储库/ dao层。根据最佳做法的建议,我不再从HibernateDaoSupport延伸到使用HibernateTemplate,而是使用SessionFactory直接使用Hibernate sessionFactory.getCurrentSession(),这应该可以正常工作使用Spring 3.0.x及更高版本。

这对整个项目来说是一个非常大的好处,因为它摆脱了由HibernateTemplate引起的所有包装代码。但是,我只是注意到我不能再调用使用@PostConstruct的Service方法(或者在XML应用程序上下文中使用bean的onStartUp属性)

例如,这个方法以前使用HibernateTemplate工作得很好,但是现在Hibernate抛出一个异常,抱怨没有绑定到该线程的会话:

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

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

    createStopListIfDoesNotExist();
    stopListService.load();

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

我可以删除此@PostConstruct方法调用...它是系统中唯一的一个。当应用程序启动以引导新应用程序的数据时调用它。大多数情况下,它在生产系统上什么都不做,但是将它用于新创建的测试和开发数据库是很方便的。

关于为什么以及如何解决它的任何想法?

谢谢!

编辑:这是我的交易管理建议配置:

<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>

1 个答案:

答案 0 :(得分:1)

HibernateDaoSupport class docs中所述,“如果传入SessionFactory,此类将创建自己的HibernateTemplate实例。默认情况下,HibernateTemplate上的'allowCreate'标志将为'true'。”这意味着在旧系统下,您的DAO可以按需打开会话,而不受任何实际控制。

当Spring管理SessionFactory时,它会安装SpringSessionContext作为Hibernate的CurrentSessionContext。现在,当您调用SessionFactory.getCurrentSession()时,SpringSessionContext在Spring管理的ThreadLocal中查找会话,如果不存在则会失败。会话通常以两种方式之一打开并放置在那里:使用open-session-in-view模式对每个新请求执行此操作,并且启动事务也是如此。在您的情况下,您没有执行代码以响应请求,因此OSIV不在运行中,并且您显然也不在活动事务中。使方法具有事务性将解决您的问题。