0

我制作了一个基于 Maven+Spring 3.1+Spring MVC 3.1+Hibernate 4.1 的项目,如果我使用代码,则在事务中:

Session session=sessionFactory.getCurrentSession();
session.save(user);

它在 getCurrentSession() 处给出了异常:

SEVERE: Servlet.service() for servlet appServlet threw exception
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.company.cv.dao.UserDAO.saveUser(UserDAO.java:30)
    at com.company.cv.service.UserService.saveUser(UserService.java:20)
    at com.company.cv.HomeController.saveUser(HomeController.java:44)
    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.doPost(FrameworkServlet.java:789)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
    at java.lang.Thread.run(Thread.java:662)

但是如果我使用 openSession 而不是 getCurrentSession 没有异常并且代码事务成功完成:

    Session session = sessionFactory.openSession();
    session.save(user);

是什么原因?谢谢您的帮助

我的 applicationContext.xml:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://localhost:3306/companycv" />
    <property name="username" value="root" />
    <property name="password" value="root" />
</bean>

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="annotatedClasses">
    <list>
        <value>com.company.cv.model.User</value>
    </list>
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.hbm2ddl.auto">create</prop>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
        </props>
    </property>
</bean>

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

servlet-context.xml:

<!-- 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>

<context:component-scan base-package="com.company.cv" />

我的服务代码:

@Service
public class UserService implements UserServiceIntf{

    @Autowired
    UserDAOIntf userDAO;

    @Transactional
    public void saveUser(User user) {
        userDAO.saveUser(user);
    }
}

我的 DAO 代码:

@Repository
public class UserDAO implements UserDAOIntf {

    @Autowired
    SessionFactory sessionFactory;

    public void saveUser(User user) {
        Session session=sessionFactory.getCurrentSession();
        session.save(user);
    }
}
4

3 回答 3

1

@Transactional您需要在调用 DAO 方法的服务方法上方添加注释save。由于您已txManager在应用程序上下文中定义,因此您无需手动管理事务。

于 2012-09-14T23:49:35.877 回答
1

我观察到您做错的一件事是您将 Hibernate 事务 API 的使用与 Spring 托管事务管理抽象混合在一起。严格不建议这样做。

Session session=sessionFactory.getCurrentSession();
Transaction tx=session.beginTransaction(); // This is using Hibernate transaction API
session.save(user);
sessionFactory.getCurrentSession().save(user);
tx.commit();// This is using Hibernate transaction API

在上面的代码中,您使用 hibernate 事务 api 来管理事务以及 Spring 事务管理(当您使用事务注释注释您的 Service 方法时)

你只需要使用这个

Session session=sessionFactory.getCurrentSession();
session.save(user);
sessionFactory.getCurrentSession().save(user);

同样正如其他人所指出的,您列出了重复的数据源定义。而且您提到您无法获得没有意义的 sessionFactory,因为它是通过 Spring 注入的,并且您说在另一种情况下您可以访问 sessionFactory。没有理由发生这种情况。

更新

所以你说你在这两种情况下都可以访问 sessionFactory,但在 getCurrentSession 的情况下它不起作用。进行了所有建议的更改后,最好的建议是通过在 log4j 配置中启用 Hibernate 日志记录和 Spring 框架日志记录(如果您使用的是 log4j)跟踪相关活动,以了解幕后发生的事情。

您的 log4j 配置文件将是这样的

# Direct log messages to a log file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=<file-path>
log4j.appender.file.MaxFileSize=5MB
log4j.appender.file.MaxBackupIndex=1
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n


# Root logger
log4j.rootLogger=INFO, file

# Hibernate and Spring logging
log4j.logger.org.hibernate=DEBUG
log4j.logger.org.springframework.transaction=DEBUG

这会给你一个清晰的画面。

于 2012-09-16T15:24:22.697 回答
0

这是因为 Hibernate4。如果您像我首先应该做的那样查看 Hibernate4 DOC (:D) Hibernate4,那么您每次都有 openSession。我认为 Hibernate 的人做到了,所以像我这样的菜鸟每次都会被迫使用新的会话。因为会话不是线程安全的。仅供参考Hibernate openSession() 与 getCurrentSession()

于 2013-03-22T13:28:38.013 回答