Java Spring MVC - 没有 Hibernate Session 绑定到线程

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18829172/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 11:27:01  来源:igfitidea点击:

Spring MVC - No Hibernate Session bound to thread

javaspringhibernatespring-mvc

提问by user2784083

I have problem with session in hibernate:

我在休眠中遇到会话问题:

INFO: Starting ProtocolHandler ["http-bio-8080"]
2013-09-10 16:23:11 org.apache.catalina.startup.Catalina start
 INFO: Server startup in 4000 ms
2013-09-10 16:23:13 org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [appServlet] in context with path [/portal] threw          exception [Request processing failed; nested exception is org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here] with root cause
org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
    at org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:63)
    at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:687)
    at com.myportal.portal.model.HibernateDao.getSessionFactory(HibernateDao.java:31)
    at com.myportal.portal.model.HibernateDao.testowa(HibernateDao.java:46)
    at com.myportal.portal.controllers.HomeController.home(HomeController.java:35)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

I've read something about this problem but the solutions don't work in my case.

我已经阅读了有关此问题的内容,但解决方案在我的情况下不起作用。

My Dao class:

我的道课:

package com.myportal.portal.model;
import org.hibernate.classic.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.myportal.portal.entity.User;

@Repository
@Transactional(propagation=Propagation.REQUIRED)
public class HibernateDao {
    @Autowired
    private SessionFactory sessionFactory;


    public HibernateDao()
    {

    }
    public HibernateDao(SessionFactory sessionFactory)
    {
        this.sessionFactory = sessionFactory;
    }
    private Session getSessionFactory()
    {
        return sessionFactory.getCurrentSession();
    }

    private void setSessionFactory(SessionFactory sessionFactory)
    {
        this.sessionFactory = sessionFactory;
    }

    public void testowa()
    {
        User u = new User();
        //SessionFactory sf = getSessionFactory();
        //Session s = sf.openSession().beginTransaction()

        // problem with this
        Session session = getSessionFactory();
        //session.save(u);

    }
}

root-context.xml

根上下文.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- Root Context: defines shared resources visible to all other web components -->


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

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost/hibernate1"/>
    <property name="username" value="root2"/>
    <property name="password" value=""/>
    <property name="initialSize" value="5"/>
    <property name="maxActive" value="10"/>
</bean>    

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
   <property name="dataSource" ref="dataSource"/>
   <property name="packagesToScan" value="com.spoleczniak.projekt.model"/>
   <property name="hibernateProperties">
       <props>
           <prop key="dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
           <prop key="show_sql">true</prop>
       </props>
   </property>
</bean>

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

     <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

</beans>

servlet-context.xml

servlet-context.xml

    <!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->

    <!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
    <context:annotation-config/>
<context:component-scan base-package="com.myportal.portal" />

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
    <resources mapping="/resources/**" location="/resources/" />

    <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
    <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />
    </beans:bean>

I use it like this:

我像这样使用它:

@Controller
public class RegisterController {

    @Autowired
    private HibernateDao hibernateDao;

    @RequestMapping(value="/register")
    public String registerForm()
    {
        hibernateDao.testowa();
        return "register";
    }
}

How can I fix it?

我该如何解决?

I change DAO and create UserService, but error still appears :

我更改了 DAO 并创建了 UserService,但仍然出现错误:

DAO:

道:

@Repository
public class HibernateDao {
    @Autowired
    private SessionFactory sessionFactory;


    public HibernateDao()
    {

    }
    public HibernateDao(SessionFactory sessionFactory)
    {
        this.sessionFactory = sessionFactory;
    }
    private Session getSessionFactory()
    {
        return sessionFactory.getCurrentSession();
    }

    private void setSessionFactory(SessionFactory sessionFactory)
    {
        this.sessionFactory = sessionFactory;
    }

    public void testowa()
    {
        User u = new User();
        //SessionFactory sf = getSessionFactory();
        //Session s = sf.openSession().beginTransaction()

        // problem with this
        Session session = getSessionFactory();
        //session.save(u);

    }
} 

UserService:

用户服务:

@Service
public class UserService {

    @Autowired
    private HibernateDao hibernateDao;


    @Transactional
    public void addContact() 
    {
        hibernateDao.testowa(); 
    }
}

Controller:

控制器:

@Controller
public class RegisterController {

    @Autowired
    private UserService userService;

    @RequestMapping(value="/register")
    public String registerForm()
    {
        userService.addContact();
        return "register";
    }
}

采纳答案by Sotirios Delimanolis

What's happening is your servlet-context.xmlis overwriting beans in your root-context.xmlbecause it's declaring a component-scanfor the package containing the @Repositoryclass. In servlet-context.xml, you have

发生的事情是您servlet-context.xml正在覆盖您中的 bean,root-context.xml因为它component-scan为包含@Repository该类的包声明了 a 。在servlet-context.xml,你有

<context:component-scan base-package="com.myportal.portal" />

while your HibernateDaoclass is in com.myportal.portal.model. This ApplicationContextwill create a HibernateDaobean without transaction management, since it doesnt have <tx:annotation-driven>. The HibernateDaobean that is autowired in your @Controlleris this one, not the one from the root-context.xml(which has transaction management).

当你的HibernateDao班级在com.myportal.portal.model. 这ApplicationContext将创建一个没有事务管理HibernateDaobean ,因为它没有。在您的自动装配的bean 是这个bean,而不是来自(具有事务管理)的bean 。<tx:annotation-driven>HibernateDao@Controllerroot-context.xml

To fix this, you will want to start by adding

要解决此问题,您需要先添加

<context:component-scan base-package="com.myportal.portal.model" />

to your root-context.xmland removing <context:annotation-config/>(it is redundant). You then want to modify the component-scanin the servlet-context.xmlto something more specific that doesn't contain the package of the @Repositoryclasses

到您的root-context.xml和删除<context:annotation-config/>(这是多余的)。那么你要修改component-scanservlet-context.xml更具体的东西,不包含的包@Repository

<context:component-scan base-package="com.myportal.portal.controllers" />

that package would contain your @Controllerclasses. You also don't need the <context:annotation-config>.

该包将包含您的@Controller类。您也不需要<context:annotation-config>.

回答by ElderMael

No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here

This means that there is no current transaction within that thread.

这意味着该线程中没有当前事务。

As you corrected me the class is annotated with @Transactional but I see that it does not implement an interface. It may happen that the generated proxy does not expose the annotation as happens when you annotate a controller without it implementing an interface.

正如您纠正我的那样,该类使用 @Transactional 进行了注释,但我发现它没有实现接口。可能发生的情况是,生成的代理不会像在没有实现接口的情况下注释控制器时那样公开注释。

See why CGLIB proxies do not retain certain annotations.

了解为什么 CGLIB 代理不保留某些注释

回答by instancenow

During beans instantiation servlet-context.xmlis read and beans with @Controller, @Service, @Repositoryare instantiated.

在 bean 实例化期间servlet-context.xml读取并实例化带有@Controller, @Service,@Repository的 bean。

Now when application-context.xml(which has <tx:annotation-driven />) is read the beans are already there and so doesn't get transactional behavior. Make the package in servlet-context.xmlspecific to UI like controller/ Or exclude the Service, Repository package from component-scan.

现在,当application-context.xml(有<tx:annotation-driven />)被读取时,bean 已经存在,因此不会出现事务行为。制作servlet-context.xml特定于 UI的包,如控制器/或从组件扫描中排除服务、存储库包。

<context:component-scan base-package="com.java.controllers"/>