关于Could not obtain transaction-synchronized Session for current thread 这个异常。
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 这个异常。的更多相关文章
- Hibernate4中使用getCurrentSession报Could not obtain transaction-synchronized Session for current thread
架个spring4+hibernate4的demo,dao层直接注入的sessionFactory,然后用getCurrentSession方法获取session,然后问题来了,直接报错: Could ...
- 关于Hibernate Could not obtain transaction-synchronized Session for current thread
转载自 http://blog.csdn.net/flyjiangs/article/details/51537381 最近几年一直再搞android,最近闲下来了,顺便玩一下web. 整了个最新版本 ...
- 记一次bug思考过程:HibernateException: Could not obtain transaction-synchronized Session for current thread
场景:把从客户端提交的任务放到线程池执行 异常:HibernateException: Could not obtain transaction-synchronized Session for cu ...
- Could not obtain transaction-synchronized Session for current thread原因及解决方案
在开发中,碰到到了Could not obtain transaction-synchronized Session for current thread异常,因此特意记录下. 一.问 ...
- org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
spring与hibernate整合报错 org.hibernate.HibernateException: Could not obtain transaction-synchronized Ses ...
- Hibernate Could not obtain transaction-synchronized Session for current thread问题处理
项目通过Hibernate查询时报出如下错误: Hibernate Could not obtain transaction-synchronized Session for current thre ...
- Could not obtain transaction-synchronized Session for current thread 错误的解决方法!
BsTable bsTable = new BsTable(); // String time = request.getParameter("date"); String tim ...
- 关于spring3中No Session found for current thread!and Transaction的配置和管理(转)
今天我是特别的郁闷,本来项目做到一半,以前都好好的,结果下午就出现问题,苦逼的到现在才解决.它出现问题的时候都一声不坑, ,(天啦,现在才发现CSDN啥时候把QQ表情给整过来了)就在注册用户的时候,咦 ...
- Spring+Hibernate4 Junit 报错No Session found for current thread
论坛上有另外一篇更全面的帖子,jinnianshilongnian写的:http://www.iteye.com/topic/1120924 本文的环境是: spring-framework-3.1 ...
随机推荐
- css选择器星号(*)
1.星号(*)选择器的优先级 css的(*)选择器,也是通用选择器,对所有的页面元素(html,title,style,body,div,p……)应用样式,级别最低 在选择器的级别中:在元素名< ...
- grep常用命令总结与基础正则
grep 'str'用来选取含有str的行 参数: -v 反向选取 -n 显示行号 -c 计算查找到字符串的次数 -i 选取时不区分大小写 基础正则表达式符: [list] 从字符集合里选出任意一个字 ...
- SQL 工具系列一
1.误删除数据恢复篇 ApexSQL Recover 可以恢复Delete Truncate drop,恢复 二进制大型对象 测试版本 每10行才会恢复 评估版本下载地址:只能用14天 所以基 ...
- show_space
create or replace procedure show_space( p_segname_1 in varchar2,p_space in varchar2 default 'AUTO',p ...
- JavaScript中 运算符
运算符对一个或多个变量或值(操作数)进行运算,并返回一个新值 根据所执行的运算,运算符可分为以下类别: (1) 算术运算符 (2) 比较运算符 运算符 说 明 示 例 == 等于. 如果两个操作数相 ...
- Hibernate学习1--对象持久化的思想
前些天开始接触hibernate,想想以前直接用c3p0进行笨拙而繁杂的数据库操作就觉得生无可恋了,也正因如此,在刚刚接触hibernate的我,便强烈地喜欢上这种偷懒而优雅的面向对象式操作数据库的方 ...
- 二、spring-boot-devtools热部署
springboot提供了热部署,需要添加依赖: <dependency> <groupId> org.springframework.boot</groupId> ...
- Eclipse 入手配置
工欲善其事,必先利其器 在安装eclipse后进行简单的配置能够为以后的开发提高不少效率,这里慢慢先记录自己的经验. 一.编码配置 utf-8 1.worksplace: 首先设置就是workspac ...
- js对象之间的继承
js的对象之间的继承抛弃了原型与构造器的概念,而转为字面量对象之间进行属性拷贝的方式进行继承. 首先我们来写一个封装好的继承函数: function extend(parent){ var child ...
- Yii2.0 新建项目通用准备工作
1.设置 cookieValidationKey 在 config/web.php 中 config 里有 components项中request有个cookieValidationKey需要配置参数 ...