【问题标题】:Spring and hibernate: No Session found for current threadSpring和休眠:没有为当前线程找到会话
【发布时间】:2012-05-05 02:57:51
【问题描述】:

我得到以下错误

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:1024)
at com.fexco.shoptaxfreemobile.service.ProfileService.registerVisitor(ProfileService.java:57)
at com.fexco.shoptaxfreemobile.controller.ProfileController.registerVisitor(ProfileController.java:91)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:213)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:126)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:770)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at com.fexco.shoptaxfreemobile.jsonp.JsonpCallbackFilter.doFilter(JsonpCallbackFilter.java:33)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:928)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:987)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:539)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:300)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)

服务类

@Service
public class ProfileService {

    @Resource(name = "mySessionFactory")
    private SessionFactory sessionFactory;

    @Autowired
    private ProfileDao profileDao;

    private class CountrySorter implements Comparator<Country> {
        @Override
        public int compare(Country country1, Country country2) {
            if ( country1.getId().compareTo(new Long (3)) < 0){
                return country1.getId().compareTo(country2.getId());
            }
            return country1.getName().compareToIgnoreCase(country2.getName());
        }               
    }

    public List<Country> getCountries() {

        List<VisitorCountry> visitorCountries = profileDao.getAllCountries();       

        List<Country> countries = new ArrayList<Country>();
        for ( VisitorCountry country : visitorCountries){
            countries.add(country.getCountry());
        }

        Comparator<Country> comparator = new CountrySorter();       
        Collections.sort(countries, comparator);

        return countries;
    }

    public RegisterResponse registerVisitor(JsonVisitor visitorDetails){
        Visitor storedVisitor = (Visitor) sessionFactory.getCurrentSession().get(Visitor.class, visitorDetails.getTfscNumber(), LockMode.NONE);
        if ( storedVisitor == null){
            storedVisitor = new Visitor(visitorDetails);
        }else{
            storedVisitor.setVisitorDetails(visitorDetails);    
        }

        try{
            sessionFactory.getCurrentSession().saveOrUpdate(storedVisitor);

        }catch(Exception ex){
            return new RegisterResponse(false, "Failed To Register Card. Please Try Again Later.", visitorDetails);
        }

        return new RegisterResponse(true, "", visitorDetails);

    }
}

DAO 类的一点

@Service
@Transactional
public class ProfileDao {

    @Resource(name = "mySessionFactory")
    private SessionFactory sessionFactory;

    public List getAllCountries(){

        List<VisitorCountry> visitorCountries = sessionFactory.getCurrentSession()
        .getNamedQuery("GET_ALL_COUNTRIES").list();

        return visitorCountries;

    }

    public List<Retailer> getRetailerByRetailerNumber(String retailerNo) {

        List<Retailer> retailerByRetailerNumber = sessionFactory.getCurrentSession()
        .getNamedQuery("FindRetailerByRetailerNo").setString("retailerNo", retailerNo).list();

        return retailerByRetailerNumber;
    }

我的 application-context.xml 中有这个

<tx:annotation-driven transaction-manager="transactionManager"/>

<bean id="mySessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="myDataSource" />
    <property name="configLocation" value="classpath:hibernate.cfg.xml" />
    <property name="hibernateProperties">
        <value>
            <![CDATA[
        hibernate.show_sql=true
        hibernate.format_sql=true
        hibernate.cache.provider_class=org.hibernate.cache.NoCacheProvider
        ]]>
        </value>
    </property>
</bean>

谁能发现我为什么会收到以下错误?

【问题讨论】:

  • jordan002 的答案是正确的,但“真正的”问题是,您不是在您的服务中调用 DAO,而是从服务类访问数据库......另一方面,通常您希望服务方法以事务方式行事,而不仅仅是 DAO 方法 - 如果您在服务方法中有 2 次更新,而第二次更新失败,则事务不会帮助您使数据库保持一致(但这取决于您的业务逻辑)。

标签: spring hibernate sessionfactory


【解决方案1】:

您使用 @Transactional 注释了您的 Dao 类,而不是您的服务类。行:

Visitor storedVisitor =
    (Visitor) sessionFactory.getCurrentSession().get(Visitor.class,
            visitorDetails.getTfscNumber(), LockMode.NONE);

要求您参与交易。

您可以通过在 ProfileService 类中添加 @Transactional 注释来解决此问题,或者只添加 registerVisitor() 方法。

【讨论】:

  • 这更进一步,有助于让休眠状态写入更新/删除。
【解决方案2】:

我通过以下 2 个步骤解决了同样的问题

  1. 按照建议将@Transactional 放置在服务方法上 jordan002 在此页面上的回答中。

  2. 还有一件事,如果你有 2 个配置文件:说 application-context.xml(对于数据库和应用程序上下文特定 配置)和webmvc-context.xml(对于特定的网络/控制器 配置),那么您应该为您的 控制器和 dao。

    webmvc-context.xmlapplication-context.xml 之后加载。 我认为 DAO 类首先加载了事务引用 当 application-context.xml 被加载,但它被替换为 另一个对象,没有事务引用,当 webmvc-context.xml 已加载。

    无论如何,我解决了扫描特定包的问题:

    <context:component-scan base-package="com.app.repository" />
    

    application-context.xml

    <context:component-scan base-package="com.app.web" />
    

    webmvc-context.xml

【讨论】:

    【解决方案3】:

    使用 @Repository 更改 DAO 的注释

    @Repository
    public class ProfileDao { 
    .
    .
    .
    }
    

    然后让你的服务方法@Transactional 像这样

    @Transactional
    public List<Retailer> getRetailerByRetailerNumber(String retailerNo) {}
    

    【讨论】:

      【解决方案4】:

      我通过以下两步解决了上述问题

      1-在调用 DAO 方法的服务方法中添加 @Transactional 支持

      2-通过这种方式导入spring-servlet.xml中的applicationContext.xml

       <import resource="applicationContext.xml" />
      
      <mvc:annotation-driven />
      <context:component-scan base-package="com.json.api.*" />
      <!--Third Party Integration should be injected in xml start here -->
          <bean id="integrationInterface" class="com.json.api.IntegerationInterface"></bean>
      <!--Third Party Integration should be injected in xml start here -->
      <mvc:interceptors>
          <bean id="apiServiceInterceptor" class="com.json.api.interceptor.ApiServiceInterceptor"></bean>
      </mvc:interceptors>
      <!--To Enable @Value to map key with provided fields for property files -->
      <context:property-placeholder />
      

      它消除了在 spring-servlet.xml 和 applicationContext.xml 两个地方扫描包的需要

      【讨论】:

        【解决方案5】:

        我知道这是一个很老的问题,但我遇到了这个问题,发现如果您使用的是 Spring-Java 配置,那么解决方案有几个部分。某些配置与控制器的相对放置很重要。

        首先是CoreConfiguration

        @Configuration
        public class CoreConfiguration {
        @Bean          
        public LocalSessionFactoryBean sessionFactory() {
            LocalSessionFactoryBean factoryBean = new org.springframework.orm.hibernate4.LocalSessionFactoryBean();
            String annotatedPckgs[] ={"org.tigersndragons.reports.model.warehouse"};
            factoryBean.setAnnotatedPackages(annotatedPckgs);           
            Properties hibernateProperties = new Properties();
            try {
                hibernateProperties.load(this.getClass().getResourceAsStream("props/hibernate.properties"));        
                factoryBean.setHibernateProperties(hibernateProperties);
            } catch (IOException e) { }
            factoryBean.setPackagesToScan("org.telligen.reports.model.warehouse");
            factoryBean.setDataSource(warehouseDataSource());//("jdbc/warehouse");
            try {
                factoryBean.afterPropertiesSet();
            } catch (IOException e) {       }
            return factoryBean;
        }
        @Bean
        public WarehouseDAO getWarehouseDAO(){
            WarehouseDAO wrhsDao = new WarehouseDAO();
            wrhsDao.setSessionFactory(sessionFactory().getObject());
            return wrhsDao;
        }
        

        ...

        @Configuration
        public class ScheduleConfiguration {
        private static Logger logger = LoggerFactory.getLogger(ScheduleConfiguration.class);
        
        @Autowired
        private CoreConfiguration coreConfiguration;
        
        
        @Bean
        public HandlerMapping handlerMapping(){
            DefaultAnnotationHandlerMapping mapping =  new DefaultAnnotationHandlerMapping();
            mapping.setInterceptors(new Object []{coreConfiguration.openSessionViewInterceptor()});
            return mapping;
        }
        
        @Bean
        public HandlerAdapter handerAdapter(){
            return new AnnotationMethodHandlerAdapter();
        }
        
        @Bean
        public ScheduleController scheduleController() throws Exception{
            ScheduleController controller = new ScheduleController();
                controller.setWrhsDao(coreConfiguration.getWarehouseDAO());
            return controller;
        }
        
         ...
        

        在控制器中,我必须设置

        @Controller
        @RequestMapping
        public class ScheduleController {
        private static Logger logger = LoggerFactory.getLogger(ScheduleController.class);
        
        private WarehouseDAO wrhsDao;
            @RenderMapping
        @RequestMapping("VIEW")
        public String viewSchedule(Map<String, Object> modelMap){...}
        
        public void setWrhsDao(WarehouseDAO wrhsDao) {
            this.wrhsDao = wrhsDao;
        }
        }
        

        WarehouseDAO 有 @Repository 注释,而 SessionFactory 没有自动装配。

        希望这可以帮助其他有类似问题的人。

        【讨论】:

          【解决方案6】:

          我将添加一些我花了一些时间进行调试的内容:不要忘记@Transactional 注释仅适用于“公共”方法。

          我把一些@Transactional 放在“受保护”的上面,然后得到了这个错误。

          希望对你有帮助:)

          http://docs.spring.io/spring/docs/3.1.0.M2/spring-framework-reference/html/transaction.html

          方法可见性和@Transactional

          当使用代理时,你应该应用@Transactional注解 仅适用于具有公共可见性的方法。如果您确实注释受保护, 带有 @Transactional 注释的私有或包可见方法, 没有引发错误,但带注释的方法没有表现出 配置的事务设置。考虑使用 AspectJ(参见 下面)如果您需要注释非公共方法。

          【讨论】:

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