Could not obtain transaction-synchronized Session for current thread 这个异常之前非常让我头大。对于网上的各种说法都试了一下反正都不行。现在终于使这个异常消失了,但是现在(2017-7-8)还搞不清真正的原因。

这是异常的一部分。

org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:988)
at com.zcd.ssh.dao.impl.BaseDao.getSession(BaseDao.java:14)
at com.zcd.ssh.dao.impl.DepartmentDaoImpl.save(DepartmentDaoImpl.java:16)
at com.zcd.ssh.test.SSHTest.testCRUD(SSHTest.java:42)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

现在先把我猜测的原因写下来,之后如果有新发现再来这里更新这篇文章。

一、当我整合 Spring 和 Hibernate 的时候先配置好 IOC 容器的 applicationContext.xml 文件中的部分内容,创建实体类 Employee 类和Department类, Dao层的EmployeeDao类和DepartmentDao类等等,进行JUnit测试。

==========================================================================

applicationContext.xml 文件的部分内容。连接数据库需要的 db.properties 文件就不贴出来。

<!-- 扫描包 -->
<context:component-scan base-package="com.zcd.ssh"></context:component-scan> <!-- 导入资源文件: db.properties文件 -->
<context:property-placeholder location="classpath:db.properties"/> <!-- 配置数据源,使用c3p0数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${user}"></property>
<property name="password" value="${password}"></property>
<property name="driverClass" value="${driverClass}"></property>
<property name="jdbcUrl" value="${jdbcUrl}"></property>
<property name="maxPoolSize" value="${maxPoolSize}"></property>
<property name="minPoolSize" value="${minPoolSize}"></property>
<property name="initialPoolSize" value="${initialPoolSize}"></property>
<property name="acquireIncrement" value="${acquireIncrement}"></property>
</bean> <!-- 配置SessionFactory 使用LocalSessionFactoryBean-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
<property name="mappingLocations" value="classpath:com/zcd/ssh/beans/*.hbm.xml"></property>
</bean>

==========================================================================

BaseDao类

/**
* 其他Dao类通用的方法。
* @author ZCD
*/
@Repository
public class BaseDao
{
@Autowired
private SessionFactory sessionFactory; /**
* 获取当前线程的Session。
* @return 返回当前线程的Session
*/
public Session getSession()
{
return sessionFactory.getCurrentSession();
}
}

==========================================================================

DepartmentDaoImpl类。

@Repository
public class DepartmentDaoImpl extends BaseDao implements DepartmentDao
{
@Override
public boolean save(Department department)
{
getSession().save(department); return true;//暂时返回true。
} @Override
public boolean delete(Integer id)
{
String hql = "DELETE FROM Department d WHERE d.id = ?"; getSession().createQuery(hql).setInteger(0, id); return true; //暂时返回true。
} @Override
public Department getDepartment(Integer id)
{
String hql = "FROM Department d WHERE d.id = ?"; Department department = (Department)getSession().createQuery(hql).setInteger(0, id); return department;
} @Override
public ArrayList<Department> getDepartments()
{
String hql = "FROM Department d"; ArrayList<Department> departments = (ArrayList<Department>)getSession().createQuery(hql).list(); return departments;
}
}

==========================================================================

@Repository
public class EmployeeDaoImpl extends BaseDao implements EmployeeDao
{ @Override
public boolean save(Employee employee)
{
getSession().save(employee); return true; //暂时返回true。
} @Override
public boolean delete(Integer id)
{
String hql = "DELETE FROM Employee e WHERE e.id = id"; getSession().createQuery(hql).setInteger(0, id).executeUpdate(); return true; //暂时返回true。
} @Override
public Employee getEmployee(Integer id)
{
String hql = "FROM Employee e WHERE e.id = ?"; Employee employee = (Employee) getSession().createQuery(hql).setInteger(0, id).uniqueResult(); return employee;
} @Override
public ArrayList<Employee> getEmployees()
{
String hql = "FROM Employee e"; ArrayList<Employee> employees = (ArrayList<Employee>) getSession().createQuery(hql).list(); return employees;
}
}

==========================================================================

进行单元测试时出现了异常。

public class SSHTest
{
private ApplicationContext ac;
private DataSource dataSource;private DepartmentDao departmentDao; {
ac = new ClassPathXmlApplicationContext("applicationContext.xml"); dataSource = ac.getBean(DataSource.class); departmentDao = ac.getBean(DepartmentDao.class);
} /*
* 测试是否能正常连接数据库,并且自动生成数据表。
*/
@Test
public void testConnection() throws SQLException
{
System.out.println(dataSource.getConnection().getClass().getName());
} /*
* 测试DepartmentDao类的增删改查功能。
* 当我测试一下保存一个部门对象时,就抛出了上述异常。
*/
@Test
public void testCRUD()
{
departmentDao.save(new Department(102, "财务部"));
}
}

==========================================================================

二、当我完善了我的 applicationContext.xml文件,并且创建Service层等等后,在进行上述单元测试时就能够正常执行操作。

在applicationContext.xml中添加了一下内容。

<!-- 使用Spring的声明式事务 -->

    <!-- 1、配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean> <!-- 2、配置事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice> <!-- 3、配置事务切点,并且将事务切点和事务通知关联起来。 -->
<aop:config>
<aop:pointcut expression="execution(* com.zcd.ssh.service.*.*(..))" id="txPointcut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>

==========================================================================

Service层的 OperateDepartmentService 类其实和Dao层的 DepartmentDao 类基本没区别。为了使这个项目的结构完整才添加了。

@Service
public class OperateDepartmentService
{
@Autowired
private DepartmentDao departmentDao; /**
* 保存部门对象。保存新建的部门或修改的部门对象。
* @param department 被保存的部门对象。
* @return 保存成功返回true,否则返回false。
*/
public boolean save(Department department)
{
boolean success = departmentDao.save(department); return success;
} /**
* 根据部门id删除部门对象。
* @param id 部门id.
* @return 删除成功返回true,否则返回false。
*/
public boolean delete(Integer id)
{
boolean success = departmentDao.delete(id); return success;
} /**
* 根据部门id查询部门对象。
* @param id 部门id。
* @return 返回一个部门对象。
*/
public Department getDepartment(Integer id)
{
Department department = departmentDao.getDepartment(id); return department;
} /**
* 查询所有部门对象。
* @return 返回所有部门对象。
*/
public ArrayList<Department> getDepartments()
{
ArrayList<Department> departments = departmentDao.getDepartments(); return departments;
}
}

==========================================================================

再次进行单元测试就能正常进行操作了。

@Test
public void testCRUD()
{
operateDepartmentService.save(new Department(101, "销售部"));
}

==========================================================================

                                    新发现

==========================================================================

三、在 Spring 整合 Hibernate 后进行单元测试什么都没有出现问题。但是加入SpringMVC后感觉自己写的代码都没有错误。

==========================================================================

下面是SpringMVC的配置文件。

    <!-- 扫描包 -->
<context:component-scan base-package="com.zcd.ssh" use-default-filters="true">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan> <!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean> <mvc:default-servlet-handler/> <mvc:annotation-driven></mvc:annotation-driven>

==========================================================================

web.xml 文件。

<!-- 配置contextConfigLocation -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param> <!-- Bootstraps the root web application context before servlet initialization -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener> <!-- 配置DispatcherServlet -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet> <servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<!-- 拦截所有请求 -->
<url-pattern>/</url-pattern>
</servlet-mapping> <filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<!-- 拦截所有请求 -->
<url-pattern>/*</url-pattern>
</filter-mapping>

==========================================================================

jsp页面的请求。

<a href="employees">所有员工</a>

==========================================================================

@Controller
public class EmployeeController
{
@Autowired
private OperateEmployeeService employeeService; @RequestMapping(value="/employees", method=RequestMethod.GET)
public String list(Map<String, Object> map)
{
ArrayList<Employee> employees = employeeService.getEmployees();
map.put("employees", employees); return "employees";
}
}

我以上的代码感觉都没有问题。但却总是抛出异常。真正的原因就是加入SpringMVC后,我又配置了一个SpringMVC的IOC容器文件:springmvc.xml 。此时有两个IOC容器的配置文件。一个是SpringMVC的,一个是Spring的。这两个文件都对bean进行了自动扫描。

springmvc.xml 文件扫描的代码如下。这里是只扫描@Controller 注解的类。

    <!-- 扫描包 -->
<context:component-scan base-package="com.zcd.ssh">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>

applicationContext.xml 文件的扫描的代码如下。这是除了@Controller 注解的类都扫描。看似很完美。刚好所有的bean都扫描完了,每个bean都只会创建一个实例。

    <!-- 扫描包 -->
<context:component-scan base-package="com.zcd.ssh">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>

但是真的只会创建一个实例吗?在每个bean的无参构造器都打印一句话,然后运行程序。发现,除了 @Controller 注解的类,其他的类都创建了两个实例。也就是说我们在Spring IOC容器里声明的SessionFactory这个bean也创建了两个实例。问题可能就是因为创建了两个SessionFactory的实例,所以不能获取当前线程的Session。

此时只要在springmvc.xml扫描<context:component-scan>节点加上use-default-filters="false" 这个属性。就可以了。因为不加这个它还是会使用默认的过滤器。还是会扫描到其他的Spring IOC容器中的bean。具体修改如下

    <!-- 扫描包 --><!-- 加上 use=default-filters="false" 这个属性就可以了-->
<context:component-scan base-package="com.zcd.ssh" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>

====================================================================

2017-09-25

四、总结

观察了一下,会出现上述异常原因:

  一、因为没有通过Service层来访问数据库,更准确的说没有使用声明式事务。因为Hibernate 使用Spring的声明式事务,事务的切点是在Service层里的所有类的所有方法。所以如果直接通过Dao层操作数据库就相当于没有使用事务,如果事务切点配置错误也有可能出现异常。还有,如果一个业务层(Service层)中的某一个类已经使用@Service注解,但是事务切点没有作用在这个类的方法上,那么也就相当于没有使用事务,也会出现上述异常。

以上猜测不知道正不正确,反正异常消失了。^o^

关于Could not obtain transaction-synchronized Session for current thread 这个异常。的更多相关文章

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

    架个spring4+hibernate4的demo,dao层直接注入的sessionFactory,然后用getCurrentSession方法获取session,然后问题来了,直接报错: Could ...

  2. 关于Hibernate Could not obtain transaction-synchronized Session for current thread

    转载自 http://blog.csdn.net/flyjiangs/article/details/51537381 最近几年一直再搞android,最近闲下来了,顺便玩一下web. 整了个最新版本 ...

  3. 记一次bug思考过程:HibernateException: Could not obtain transaction-synchronized Session for current thread

    场景:把从客户端提交的任务放到线程池执行 异常:HibernateException: Could not obtain transaction-synchronized Session for cu ...

  4. Could not obtain transaction-synchronized Session for current thread原因及解决方案

            在开发中,碰到到了Could not obtain transaction-synchronized Session for current thread异常,因此特意记录下. 一.问 ...

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

    spring与hibernate整合报错 org.hibernate.HibernateException: Could not obtain transaction-synchronized Ses ...

  6. Hibernate Could not obtain transaction-synchronized Session for current thread问题处理

    项目通过Hibernate查询时报出如下错误: Hibernate Could not obtain transaction-synchronized Session for current thre ...

  7. Could not obtain transaction-synchronized Session for current thread 错误的解决方法!

    BsTable bsTable = new BsTable(); // String time = request.getParameter("date"); String tim ...

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

    今天我是特别的郁闷,本来项目做到一半,以前都好好的,结果下午就出现问题,苦逼的到现在才解决.它出现问题的时候都一声不坑, ,(天啦,现在才发现CSDN啥时候把QQ表情给整过来了)就在注册用户的时候,咦 ...

  9. Spring+Hibernate4 Junit 报错No Session found for current thread

    论坛上有另外一篇更全面的帖子,jinnianshilongnian写的:http://www.iteye.com/topic/1120924 本文的环境是:  spring-framework-3.1 ...

随机推荐

  1. 栈C++实现

    栈的核心是LIFO(Last In First Out),即后进先出 出栈和入栈只会对栈顶进行操作,栈底永远为0.如果是入栈,要将入栈元素赋值给栈数组,再将栈顶上移一位:出栈时要先将栈顶下移一位,再将 ...

  2. Unity3d编辑器扩展学习笔记

    编辑器扩展 1.添加菜单栏:把特性应用于静态方法 参数1:菜单名的空格后面是定义快捷键(单符号得用"_"开头,组合键%=Ctrl,#=Shift,&=Alt) 参数2:通过 ...

  3. win7(64)+vs2010+opencv2.3.1配置问题:应用程序无法正常启动0xc000007b

    根据:毛星云(浅墨)的[OpenCV入门教程之一] 安装OpenCV:OpenCV 3.0.OpenCV 2.4.8.OpenCV 2.4.9 +VS 开发环境配置 文章链接:http://blog. ...

  4. AngularJS的基础知识

    一.AngularJS指令与表达式 [AngularJS常用指令]1.ng-app:声明Angular所管辖的区域,一般写在body或HTML上,原则上一个页面只有一个.2.ng-model:把元素值 ...

  5. MSSqlServer 数据库降级及数据转移

    --MSSqlServer数据库降级及数据转移--MS SQL SERVER高版本数据库(Database_A)恢复数据到低版本数据库(Database_B)中--1.数据库结构对象(包含表.视图.函 ...

  6. Ajax发送GET、POST请求和响应XML数据案例

    1.新建工程 新建一个java web工程,新建一个Servlet文件 AServlet.java,用于返回get和post请求. public class AServlet extends Http ...

  7. JS大写转小写小写转大写,JS字符串大小写互换

    Array.prototype.map.call(str,a=>a.toUpperCase(a)==a?a.toLowerCase():a.toUpperCase()).join(''); 效果 ...

  8. The Struts dispatcher cannot be found. This is usually caused by using Struts tags without the associated filter.

    The Struts dispatcher cannot be found. This is usually caused by using Struts tags without the assoc ...

  9. 二、mysql存储引擎之InnoDB

    一.存储引擎简介 mysql采用业务逻辑和数据存储分离的架构,底层的存储引擎为上层的SQL层提供了支持:mysql采用的是插件的方式将存储引擎直接加载到正在运行的MySQL中,这是mysql的一个重要 ...

  10. Hibernate 学习(二)

    一.Hibernate 核心 API 1.Configuration 对象(配置) 配置对象是你在任何 Hibernate 应用程序中创造的第一个 Hibernate 对象,并且经常只在应用程序初始化 ...