【问题标题】:No Session found for current thread: Spring 3 and Hibernate 4 (Using @PostConstruct annotation)未找到当前线程的会话:Spring 3 和 Hibernate 4(使用 @PostConstruct 注释)
【发布时间】:2014-11-11 13:52:55
【问题描述】:

我阅读了大量有类似问题的人的帖子,但我仍然无法让我的代码正常工作。

当我将@Transactional 从 Dao 移动到服务层时,会出现“No Session found for current thread”。事实上,我确信将事务绑定到单个访问是一种资源浪费。顺便说一句,我的 web-app 配置很常见:

  • 春季 3.1.2
  • 休眠 4

我无法找出问题所在,我检查了著名的<tx:annotation-driven> 以及正确的<context:component-scan ...> 是否在正确的位置。我的猜测是 spring 需要 @Transactional 也被放置在具有会话工厂引用的类之上,但这对我来说似乎有点不合逻辑。

这是 servlet

<!-- auto-detects and registers annotated classes belonging to the base package-->
<context:component-scan base-package="com.x.y.controllers" />
<!-- flips on all the annotation-driven capabilities for Spring MVC -->
<mvc:annotation-driven />   
...

这是上下文

<!-- enables the @Transactional annotantions -->
<tx:annotation-driven transaction-manager="transactionManager"/>

<bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<!-- auto-detects and registers annotated classes belonging to the base package-->
<context:component-scan base-package="com.x.y.service" />
<context:component-scan base-package="com.x.y.aop" />
<context:component-scan base-package="com.x.y.model" />


<bean id="dataSource"
class = "com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
    <property name="driverClass" value="${database.driver.className}" />
    <property name="jdbcUrl" value="${database.uri}" />
    <property name="user" value="${database.username}" />
    <property name="password" value="${database.password}" />

    <!-- these are C3P0 properties -->       
    <property name="checkoutTimeout" value="30000" />
    <property name="initialPoolSize" value="10" />
    <property name="maxIdleTime" value="30" />
    <property name="minPoolSize" value="10" />
    <property name="maxPoolSize" value="100" />
    <property name="maxStatements" value="200" />
    <property name="testConnectionOnCheckout" value="false" />
    <property name="testConnectionOnCheckin" value="true" />
    <property name="preferredTestQuery" value="SELECT 1" />
    <property name="idleConnectionTestPeriod" value="30" />
</bean> 

<bean id="sessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">${database.hibernate.dialect}</prop>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
            <prop key="hibernate.cache.use_second_level_cache">true</prop>
            <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
            <prop key="hibernate.generate_statistics">true</prop>
            <prop key="hibernate.show_sql">false</prop>
            <prop key="hibernate.connection.SetBigStringTryClob">true</prop>
            <prop key="hibernate.jdbc.batch_size">0</prop>          
        </props>
    </property>
</bean>

这里是服务

package com.x.y.service.initialization;

@Component
public class Initializer {

    @Autowired
    @Qualifier("userDaoImpl")
    private UserDao userDao;

    @PostConstruct
    @Transactional
    public void init()
    {
        ProfiledUser admin = userDao.loadByUsername("Administrator");

        ...
    }
}

这是 DAO

package com.x.y.model.dao;

@Repository(value="userDaoImpl")
public class UserDaoImpl implements UserDao{

    @Autowired
    @Qualifier("sessionFactory")
    protected SessionFactory sessionFactory;

    public ProfiledUser loadByUsername(String username)
    {
        Session session = sessionFactory.getCurrentSession();
        Criteria criteria = session.createCriteria(ProfiledUser.class);
        criteria.add(Restrictions.eq("username", username));
        ProfiledUser user = (ProfiledUser) criteria.uniqueResult();
        if(user != null)
            return user;
        else
            return null;
    }
}

这是 stacktrace

ERROR: org.springframework.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'initializer': Invocation of init method failed; nested exception is org.hibernate.HibernateException: No Session found for current thread
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:135)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:394)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1448)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:609)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:469)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:383)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:283)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:111)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4206)
    at org.apache.catalina.core.StandardContext.start(StandardContext.java:4705)
    at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
    at org.apache.catalina.core.StandardHost.start(StandardHost.java:840)
    at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
    at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463)
    at org.apache.catalina.core.StandardService.start(StandardService.java:525)
    at org.apache.catalina.core.StandardServer.start(StandardServer.java:754)
    at org.apache.catalina.startup.Catalina.start(Catalina.java:595)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
    at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
Caused by: 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:881)
    at com.x.y.model.dao.UserDaoImpl.loadByUsername(UserDaoImpl.java:37)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:319)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:90)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at com.sun.proxy.$Proxy15.loadByUsername(Unknown Source)
    at com.x.y.service.initialization.Initializer.init(Initializer.java:46)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:346)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:299)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:132)
    ... 29 more

【问题讨论】:

    标签: java spring hibernate spring-transactions


    【解决方案1】:

    也许这是其他答案所暗示的错误配置,但是,请记住,您不应使用 @Transactional 注释您的 @PostConstruct 并期望它能够正常工作。在执行 @PostConstruct 时,不能保证您的代码使用事务语义进行检测。原因是@PostConstruct 只保证所有依赖项都被注入并且bean 构建完成,但这并不意味着完整的上下文已经完成加载(不保证事务检测已经完成)。

    如果您确实需要 @PostConstruct 中的事务,请选择程序化方式。这些只是我的两分钱,但很可能是您问题的原因

    更新

    刚刚找到一个关于它的blog,他们建议使用@PostInitialize,因为它保证在加载完整上下文后被调用

    【讨论】:

    • 这可能是个问题。请考虑我的Initializer 类应该在应用程序准备就绪时运行。可能@PostConstruct 是矫枉过正。您是否建议任何其他注释说:“好的,网络应用程序已完全加载,现在执行此方法。”
    • 是的,刚刚编辑了一个答案 @PostiInitialize 应该可以工作,如果没有,您可以注入 TransactionManager 并使用 TransactionTemplate 以编程方式处理事务(离开@PostConstruct)
    • 你赢得了比赛。这绝对是 PostConstruct 问题。使用@PostInitialize,一切都像石油一样顺利。我将更改我的问题的标题,以便人们能够正确地解决问题。
    • 不幸的是,我无法使 PostInitialize 注释工作。我注释了该方法,但很简单,它不会在启动时触发。网上资料很少,能不能给点提示?
    【解决方案2】:

    您声明了“数据源”和“会话工厂”,但缺少“事务管理器”

    尝试将其添加到 spring 上下文中:

    <bean id="transactionManager"
            class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean> 
    

    希望对你有帮助

    【讨论】:

    • 事务管理器包含在上下文中,或多或少在第 3 行,就在 &lt;tx:annotation-driven&gt; 的正下方。
    • 抱歉我没看到:-O
    【解决方案3】:

    您可以在 hibernate-context.xml 中定义事务管理器

    <tx:annotation-driven transaction-manager="hbnTransactionManager" />
        <bean id="hbnTransactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
            <property name="sessionFactory">
                <ref bean="sessionFactory" />
            </property>
        </bean>
    

    【讨论】:

    • 请注意事务管理器已经在上下文文件中。或多或少在第 3 行。
    【解决方案4】:

    由于您在 DAO 中直接使用 SessionFactory,因此您必须具有以下配置 hibernate.current_session_context_class,并且您的 SessionFactory 配置应如下所示。

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${database.hibernate.dialect}</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
                <prop key="hibernate.cache.use_second_level_cache">true</prop>
                <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
                <prop key="hibernate.generate_statistics">true</prop>
                <prop key="hibernate.show_sql">false</prop>
                <prop key="hibernate.connection.SetBigStringTryClob">true</prop>
                <prop key="hibernate.jdbc.batch_size">0</prop> 
                <!-- Add this configuration -->
                <prop key="hibernate.current_session_context_class">thread</prop>          
            </props>
        </property>
    </bean>
    

    【讨论】:

      【解决方案5】:

      我遇到了同样的问题。

      我使用的是基于注释的配置,我已经配置了会话工厂、数据源和事务管理器。但我没有在 AppConfig 类中给出 @EnableTransactionManagement 注释。

      添加事务注释后的代码如下所示。

      @Configuration
      @ComponentScan("com.bmp.*")
      @EnableWebMvc
      @PropertySource("classpath:${env}.properties")
      @EnableTransactionManagement
      public class AppConfig {
      -----
      }
      

      以上注释解决了我的问题。

      如果这解决了您的问题,请投票。

      【讨论】:

        猜你喜欢
        • 2013-11-19
        • 1970-01-01
        • 2015-05-28
        • 2014-01-10
        • 2013-06-21
        • 1970-01-01
        • 1970-01-01
        • 2014-08-16
        • 2012-06-05
        相关资源
        最近更新 更多