·使用spring和hibernate整合+struts2整合时,服务器启动没问题,访问action时报错:
HTTP Status 500 - getFlushMode is not valid without active transaction; nested exception is org.hibernate.HibernateException: getFlushMode is not valid without active transaction
首先查看自己有没有配置开启事务
首先bean.xml(spring的配置文件)如下:(我是使用注解方式配置)
[html] view plain copy
然后service上加注解:
[java] view plain copy
@Transactional
public class UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add(){
System.out.println(“service…….”);
userDao.add();
}
}
如上,我都开启了事务,还是出错。查资料查配置文件发现这一条:hibernate.cfg.xml文件中:
[html] view plain copy
thread
就是这个问题,先说一下解决方法:两种方法:
第一种:hibernate3.x及以上的版本可以直接注释掉这条代码,或者删除也行 然后测试,可以完美运行了
第二种:标签值thread改成 : org.springframework.orm.hibernate5.SpringSessionContext (因为我的hibernate是5.x的版本)最后改成:
[html] view plain copy
org.springframework.orm.hibernate5.SpringSessionContext
然后也可以完美运行
注意注意:如果修改了以后还是不能够解决这个问题,就是说还是会报那个错误,那么,服务器缓存清一下,浏览器缓存清一下
还没解决的话那就把项目运行环境改一下:如下改–》鼠标在项目上右击选择properties:
这可能是因为myeclipse环境跑飞的原因吧,它没有把最新的项目文件更新到tomcat的运行目录或者说虚拟目录下。那么我们可以手动把项目从服务器删除,然后重新部署
分析
然后,我们来看出这个错误修改的具体原因和思路
[html] view plain copy
thread
首先看这段代码的用处:
让我们在某一个上下文环境(比如说当前线程)中可通过SessionFactory.getCurrentSession()得到同一个session
我们所知道的是,hibernate中事务是需要在dao执行sql相关语句时来手动开启的,然后底层实现代码时由getCurrentSession得到的session中可以得到transaction,所以可以正常运行
错误原因:
而spring中事务是在配置文件中配置自动开启,因为由getCurrentSession得到的session中是当前线程的session,但是当前线程中没有开启事务的代码,所以不能获transaction 。然而spring+hibernate整合必须要有活动的事务才能执行dao中的方法,这个可以从报错信息中可以看出。
解决思路:
因为我们把sessionFactory的产生放在spring配置文件中,即让服务器启动时就创建这个对象,这样的话它就被存在一个上下文环境中,即在SpringSessionContext中保存
所以我们要把绑定当前线程session改成绑定这个spring上下文环境,即设置为由spring环境管理(因为事务aop也是在spring中),这时spring中的事务配置才会起作用(当然,以前是thread上下文环境的session,而事务托管在spring上下文中,当然spring无法管理到thread上下文的session的事务)。即改成这样:
[html] view plain copy
org.springframework.orm.hibernate5.SpringSessionContext
再次深入:
我们查看ThreadLocalSessionContext,JTASessionContext,ManagedSessionContext,SpringSessionContext这几个类定义发现,都实现了一个接口org.hibernate.context.spi.CurrentSessionContext它定义了单一的方法currentSession(),特定的实现用它来负责跟踪当前的上下文相关的会话。那么,线程绑定或是上下文绑定,最后都是使用实现了CurrentSessionContext接口的一个类,来跟踪session,然后我们通过这个类的对象来获得被它跟踪的session,以达到在我们定义的上下文环境中调用getCurrentSession方法获得的总是同一个session