简体   繁体   中英

Hibernate and Spring3 Transaction Management Annotation-Configuration problems: Hibernate-Exception: No Hibernate Session bound to thread

Though this question has been asked several times, after trying many of the suggested solutions I'm still having problems getting Spring 3 to work with Hibernate (and Postgres). I always get an error of the type:

org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here

as soon as I make a call to sessionFactory.getCurrentSession() in the UserDAO class which is called in the HomeController via

User user = this.userService.retrieveUser((long) 1);

I used a STS Template to create a basic Spring-MVC directory layout which looks like this:

STS 中的项目文件夹结构

Here is my servlet-context.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop 
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- 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>


<!--  Database connection  -->
<beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <beans:property name="driverClassName" value="${jdbc.driverClassName}"/>
    <beans:property name="url" value="${jdbc.url}"/>
    <beans:property name="username" value="${jdbc.username}"/>
    <beans:property name="password" value="${jdbc.password}"/>
</beans:bean>

<!-- Hibernate -->
<beans:bean id="SessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <beans:property name="dataSource" ref="dataSource" />
    <beans:property name="configLocation">
        <beans:value>hibernate.cfg.xml</beans:value>
    </beans:property>

    <beans:property name="configurationClass">
        <beans:value>org.hibernate.cfg.AnnotationConfiguration</beans:value>
    </beans:property>
    <beans:property name="hibernateProperties">
        <beans:props>
            <beans:prop key="hibernate.show_sql">true</beans:prop>
            <beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop>
            <beans:prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</beans:prop>
        </beans:props>
    </beans:property>
</beans:bean>



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

<context:property-placeholder location="jdbc.properties"/>


<context:component-scan base-package="de.codemetrix.lokalit" />

<!-- Transaction management -->
<tx:annotation-driven />

Here is my web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>

<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- Processes application requests -->
<servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>appServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

The root-context.xml does not contain any configurations.

Here is my UserService class:

@Service
@Transactional
public class UserService {
@Autowired(required=true)
private UserDAO userDAO;

@Transactional
public User createUser(User user) {
    return this.userDAO.persistOrMerge(user);
}

@Transactional(readOnly=true)
public User retrieveUser(Long id) {
    return this.userDAO.findById(id);
}

}

And here the hibernate based UserDAO:

@Repository
public class UserDAO {
@Autowired(required=true)
private SessionFactory sessionFactory;

public User findById(Long id) {
    return (User) this.sessionFactory.getCurrentSession().createQuery(
        "from User user where user.id=?").setParameter(0, id)
        .uniqueResult();
}

public User persistOrMerge(User user) {
    return (User) this.sessionFactory.getCurrentSession().merge(user);
}
}

The Error-Log is:

17.07.2011 17:21:07 org.apache.catalina.core.StandardWrapperValve invoke
SCHWERWIEGEND: Servlet.service() for servlet [appServlet] in context with path
[/lokalit] 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:700)
at de.codemetrix.lokalit.model.database.hibernate.UserDAO.findById(UserDAO.java:18)
at de.codemetrix.lokalit.model.database.UserService.retrieveUser(UserService.java:24)
at de.codemetrix.lokalit.controller.HomeController.home(HomeController.java:52)
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:616)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:426)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:414)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:562)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at com.springsource.insight.collection.tcserver.request.HttpRequestOperationCollectionValve.invoke(HttpRequestOperationCollectionValve.java:84)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:395)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:250)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:188)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:166)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:679)

I think it might have to do with <tx:annotation-driven/> not recognizing the model classes and such ignoring the the @Transactional annotations but I'm not sure about that and I don't know where to put <tx:annotation-driven/> to find those classes.

Any help with this configuration would greatly be appreciated! Thanks in advance!

EDIT: Here is the HomeController file:

@Controller
public class HomeController {

private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

private UserService userService;

@Autowired
public void setUserService(UserService userService){
    this.userService = userService;
}

/**
 * Simply selects the home view to render by returning its name.
 */
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
    logger.info("Welcome home! the client locale is "+ locale.toString());

    User user = this.userService.retrieveUser((long) 1);

    logger.info("Tried to retrieve User with ID 1: " + user.getSurname());

    return "home";
}

}

Michael H.

Your service method isn't being wrapped in a transaction. You can tell from the stack trace. There should be several stack frames related to transactions and proxying between your controller and service. What is "HomeController", and how does it get the instance of UserService that it uses? The <tx:annotation-driven/> tag/bean should occur in the same ApplicationContext where your @Transactional beans are defined, and that appears to be in your servlet-context.xml, so that should be fine.

I finally think I got what I wanted: Automatic transaction management. After reading about Springs Declarative Transaction Management and adding an AOP Proxy, I got it working. I added the following code to my servlet-context.xml and everything went fine:

<tx:advice id="txAdvice" transaction-manager="transactionManager">
 <!-- the transactional semantics... -->
 <tx:attributes>
  <!-- all methods starting with 'get' are read-only -->
  <tx:method name="get*" read-only="true"/>
  <!-- other methods use the default transaction settings (see below) -->
  <tx:method name="*"/>
 </tx:attributes>
</tx:advice>

<!-- ensure that the above transactional advice runs for any execution
of an operation defined by the FooService interface -->
<aop:config>
 <aop:pointcut id="UserServiceOperation" expression="execution(* de.codemetrix.lokalit.model.database.UserService.*(..))"/>
 <aop:advisor advice-ref="txAdvice" pointcut-ref="UserServiceOperation"/>
</aop:config>

Probably it needs some finetuning but for now it works!

@Ryan: Thanks for pointing me to transaction management!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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