Hibernate和Spring3事务管理注解-配置问题:Hibernate-Exception: No Hibernate Sessionbound to thread
尽管这个问题已经被问过好几次了,但在尝试了许多建议的解决方案之后,我仍然在让 Spring 3 与 Hibernate(和 Postgres)一起工作时遇到问题。我总是遇到这种类型的错误:
org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
一旦我在 UserDAO 类中调用 sessionFactory.getCurrentSession()
,该类通过
User user = this.userService.retrieveUser((long) 1);
我使用 STS 模板在 HomeController 中调用来创建一个基本的 Spring -MVC 目录布局如下所示:
这是我的 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 />
这是我的 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>
root-context.xml 不包含任何配置。
这是我的 UserService 类:
@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);
}
}
这里是基于 hibernate 的 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);
}
}
错误日志是:
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)
我认为这可能与
无法识别模型类有关这样就忽略了 @Transactional
注释,但我不确定这一点,也不知道该放在哪里
来查找这些类。
任何有关此配置的帮助将不胜感激!提前致谢!
编辑:这是 HomeController 文件:
@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.
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:
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的服务方法没有包含在事务中。您可以从堆栈跟踪中看出。应该有几个与控制器和服务之间的事务和代理相关的堆栈框架。什么是“HomeController”,它如何获取它使用的 UserService 实例?
标签/bean 应该出现在定义 @Transactional beans 的同一个 ApplicationContext 中,并且出现在 servlet-context.xml 中,这样应该没问题。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.我终于认为我得到了我想要的:自动事务管理。在阅读了 Springs 声明式事务管理并添加 AOP 代理之后,我开始工作了。我将以下代码添加到我的 servlet-context.xml 中,一切都很顺利:
可能它需要一些微调,但现在它可以工作了!
@Ryan:感谢您向我指出事务管理!
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:
Probably it needs some finetuning but for now it works!
@Ryan: Thanks for pointing me to transaction management!