SpringMVC中Could not obtain transaction-synchronized Session for current thread的解决方案

首先列出错误信息

org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
    at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:134)
    at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1014)
    以下错误省略

背景

已经配置了声明式事务管理,而且单独测试service方法没错,只有在SpringMVC中才会报错。

声明式事务管理的配置

spring-tx.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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- 加载配置文件 -->
    <context:property-placeholder location="classpath:jdbc.properties"
        file-encoding="utf-8" ignore-unresolvable="true" />

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="packagesToScan">
            <list>
                <!-- 可以加多个包 -->
                <value>com.gwc.learn.spring.entity</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
                <prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
                <prop key="hibernate.current_session_context_class">org.springframework.orm.hibernate4.SpringSessionContext
                </prop>
            </props>
        </property>
    </bean>

    <!-- 配置数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
        destroy-method="close" p:driverClass="${jdbc.driverClassName}"
        p:jdbcUrl="${jdbc.url}"
        p:user="${jdbc.username}" p:password="${jdbc.password}"
        p:testConnectionOnCheckout="${jdbc.c3p0.testConnectionOnCheckout}"
        p:testConnectionOnCheckin="${jdbc.c3p0.testConnectionOnCheckin}"
        p:idleConnectionTestPeriod="${jdbc.c3p0.idleConnectionTestPeriod}"
        p:initialPoolSize="${jdbc.c3p0.initialPoolSize}" p:minPoolSize="${jdbc.c3p0.minPoolSize}"
        p:maxPoolSize="${jdbc.c3p0.maxPoolSize}" p:maxIdleTime="${jdbc.c3p0.maxIdleTime}" />

    <!-- 配置Hibernate事务管理器 -->
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <!-- 配置事务异常封装 -->
    <bean id="persistenceExceptionTranslationPostProcessor"
        class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

    <!-- 配合<tx:advice>和<aop:advisor>完成了事务切面的定义 -->
    <!-- 使用强大的切点表达式是语言轻松定义目标方法 -->
    <aop:config proxy-target-class="true">
        <!-- 通过aop定义事务增强切面 -->
        <aop:pointcut expression=" execution(* com.gwc.learn.spring.service..*(..))"
            id="serviceMethod" />
        <!-- 引用事务增强 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod" />
    </aop:config>
    <!-- 事务增强 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!-- 事务属性定义 -->
        <tx:attributes>
            <tx:method name="*" />
        </tx:attributes>
    </tx:advice>

</beans>

spring-core.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:p="http://www.springframework.org/schema/p"
    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/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 不扫描Controller -->
    <context:component-scan base-package="com.gwc.learn.spring">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!-- 导入数据库的相关配置 -->
    <import resource="classpath:spring/spring-tx.xml" />

</beans>

对UserService的单独测试

package com.gwc.learn.spring.service;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.gwc.learn.spring.entity.User;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:spring/spring-core.xml" })
public class UserServiceTest {

    @Autowired
    private UserService userService;

    @Test
    public void testAddUser() {
        User user = new User();
        user.setUsername("ladygaga");
        user.setPassword("123");
        System.out.println(userService.addUser(user));
    }

}

单独测试UserService正常执行

接下来看一下在Controller中调用Service的方法

package com.gwc.learn.spring.controller.admin;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.ContextHierarchy;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextHierarchy({
        @ContextConfiguration(name = "parent", locations = "classpath:spring/spring-core.xml"),
        @ContextConfiguration(name = "child", locations = "classpath:spring/spring-mvc.xml") })
public class AddUserControllerTest {
    @Autowired
    private WebApplicationContext wac;
    private MockMvc mockMvc;

    @Before
    public void setUp() {
        mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    }

    @Test
    public void testAddUser() throws Exception {
        mockMvc.perform((post("/admin/addUser.html")
                .param("username", "ladygaga")
                .param("password", "1234")))
                .andExpect(status().isOk()).andDo(print());
    }

}

在调用的时候报错如下

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:980)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:870)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:844)
    at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:65)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
    at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:167)
    at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
    at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:155)
    中间省略
    Caused by: org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
    at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:134)
    at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1014)
    省略

关于网上的各种关于

Request processing failed; nested exception is org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread

的解决方案都不太适合我的问题。

思来想去,最后发现是父子容器的问题,这个通过对Controller的测试代码就可以看出。

根源所在

给出spring-mvc.xml的配置

    <context:component-scan base-package="com.gwc.learn.spring">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

再来看看spring-core.xml的配置

    <!-- 不扫描Controller -->
    <context:component-scan base-package="com.gwc.learn.spring">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

这就是问题的关键所在,spring-core中的UserService中的方法是有事务特性的

而spring-mvc中的UserService是没有事务特性的

我们看看spring的文档

As detailed in Section 6.15, “Additional Capabilities of the ApplicationContext”, ApplicationContext instances in Spring can be scoped. In the Web MVC framework, each DispatcherServlet has its own WebApplicationContext, which inherits all the beans already defined in the root WebApplicationContext. These inherited beans can be overridden in the servlet-specific scope, and you can define new scope-specific beans local to a given Servlet instance.

给个图片

好了,我们不应该让spring-mvc.xml去扫描Service的

解决方案

只要将spring-mvc.xml中的配置进行如下修改即可。

    <!-- 只扫描Controller,不扫描Service -->
    <context:component-scan base-package="com.gwc.learn.spring">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    </context:component-scan>

看一下运行Controller的截图

这就OK了。

参考

http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-introduction

时间: 2024-07-30 07:41:27

SpringMVC中Could not obtain transaction-synchronized Session for current thread的解决方案的相关文章

Hibernate4中使用getCurrentSession报Could not obtain transaction-synchronized Session for current thread

架个spring4+hibernate4的demo,dao层直接注入的sessionFactory,然后用getCurrentSession方法获取session,然后问题来了,直接报错: Could not obtain transaction-synchronized Session for current thread 提示无法获取当前线程的事务同步session,略微奇怪,这和事务有什么关系..然后百度一下有人说改成用openSession方法就好了,那我又百度了一下这2个方法的区别:

事务配置不对导致:?Could not obtain transaction-synchronized Session for current thread

Struts has detected an unhandled exception: Messages: ?Could not obtain transaction-synchronized Session for current thread File: org/springframework/orm/hibernate5/SpringSessionContext.java Line number: 132 Stacktraces org.hibernate.HibernateExcepti

Hibernate4运行报错Could not obtain transaction-synchronized Session for current thread

org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:134) org.hibernate.internal.SessionFactoryImpl.get

org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread

spring与hibernate整合报错 org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:134) org.hibernate.internal.S

SpringMVC4+Hibernate4运行报错Could not obtain transaction-synchronized Session for current thread

查了一下相关资料,整理如下: 原因:Hibernate4 No Session found for current thread原因 解决方法: 1.  在spring 配置文件中加入  程序代码 <tx:annotation-driven transaction-manager="transactionManager"/> 并且在处理业务逻辑的类上采用注解  程序代码 @Service public class CustomerServiceImpl implements

Could not obtain transaction-synchronized Session for current thread

配置session有误:在项目中一般都是自动打开session和关闭session,需要在web.xml中加入如下代码: <filter> <filter-name>SpringOpenSessionInViewFilter</filter-name> <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class><

org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread spring集成Hibernate sessionfactory.getcurrentSession报错

sessionFactory.getCurrentSession()是要基于事务的,解决方法为在javaconfig配置类使用@EnableTransactionManagement注解  并且配置transactionManager bean. 在报错方法中使用@Transactional注解 原文地址:https://www.cnblogs.com/alexmason236/p/9767091.html

springMVC 返回类型选择 以及 SpringMVC中model,modelMap.request,session取值顺序

springMVC 返回类型选择 以及 SpringMVC中model,modelMap.request,session取值顺序 http://www.360doc.com/content/14/0309/19/834950_359080244.shtml

关于spring3中No Session found for current thread!and Transaction的配置和管理(转)

今天我是特别的郁闷,本来项目做到一半,以前都好好的,结果下午就出现问题,苦逼的到现在才解决.它出现问题的时候都一声不坑, ,(天啦,现在才发现CSDN啥时候把QQ表情给整过来了)就在注册用户的时候,咦,后台发现咋SQL语句特么的不对劲,仔细一看数据根本就没有送到数据库去,只是简单的执行了一下查询操作,当时我就震惊了.首先就去看了Action是否没有写save方法,结果是没有任何错误.后来我再去再其他业务层是否也出现了问题,结果都能正常操作,让我哭笑不得.后来只能查配置.当时我就看到这两个配置是在