Struts2与Hibernate整合,有时会使用OpenSessionInView模式控制会话及事务,那么这时Filter的设计通常如下:
try {
打开会话;
获取事务;
chain.doFilter();
事务提交;
} catch (Exception e) {
事务回滚;
}
看似很合理,但是catch里面的语句块无法到达,即使过程中出现异常,也无法到达,原因就是事务被Struts2的拦截器捕获了,没有继续向上抛,所以这时,想通常Filter控制事务回滚,看似不太可能了,没关系,我们换个思路.....
我们可以通过interceptor来实现这个功能,即自定义一个interceptor,伪代码如下:
try {
invacation.invoke();
} catch (Exception e) {
Session session = 通过ThreadLocal获得Session;
Transaction tx = session.getTransaction();
tx.rollback();
}
之后在struts.xml中配置intercepter-stack,这里需要注意这个interceptor必须放在default-stack的下面,即interceptor-stack的最下面:
<interceptor-stack>
<interceptor-ref name="default-stack"/>
<interceptor-ref name="rollback"/>
</interceptor-stack>
然后将默认的interceptor-stack声明成这个,那么相应的Filter里面就需要改成如下形式:
doFilter() {
获取会话;
获取事务;
chain.doFilter();
if(事务没回滚) {
提交事务;
}
}
这样便可以在发现异常的时候,让事务回滚了,前提,这里的Session是利用ThreadLocal做好的线程范围的Session,这样获取Session的时候才可以保证获得的是同一个Session,但是好像现在的最新版本Hibernate已经内置了ThreadLoad的处理了,不需要我们自己来写了。
如果大家有什么更好的方法,欢迎交流。