1 使用spring的事务处理
spring自带事务处理,使用aop可以在类、方法基于xml和annotation的方式处理事务(详见上文),写下本人的spring使用annotation事务处理:
<!-- transaction --> <tx:annotation-driven transaction-manager="txManager"/> <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <aop:config> <aop:pointcut id="serviceOperation1" expression="execution(* syx.zswz.service.impl.*.*(..))" /> <aop:pointcut id="serviceOperation2" expression="execution(* syx.zswz.base.DaoBaseImpl.*(..))" /> <aop:pointcut id="serviceOperation3" expression="within(syx.zswz.service..*)" /> <aop:advisor pointcut-ref="serviceOperation1" advice-ref="txAdvice" /> <aop:advisor pointcut-ref="serviceOperation2" advice-ref="txAdvice" /> <aop:advisor pointcut-ref="serviceOperation3" advice-ref="txAdvice" /> </aop:config> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="*" /> </tx:attributes> </tx:advice>
2 使用Hibernate事务处理
因为本人spring事务处理理解的不是很深刻,所以运用起来不是那么得心应手,在加上时间比较紧,所以选择了自己比较熟悉的hbernate事务处理方法(详见上文),因为本项目中使用了spring,所以想把HibernateUtils静态类交给spring处理,在加上filter过滤所有需要事务的请求。但因为原来的filter中使用HibernateUtil是静态类,可以直接调用静态方法,但交给spring处理之后,无法正常给filter注入HibernateUtil,启动tomcat的时候就报异常了。最后使用spring委托的filter,即把filter也交给spring处理,如果没有使用struts的web项目,可以把filter、servlet等都可以交给spring处理:
web.xml
<filter> <filter-name>hibernateSessionFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetBeanName</param-name> <param-value>hibernateSessionFilter</param-value> </init-param> </filter> <filter-mapping> <filter-name>hibernateSessionFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
beans.xml部分
<!-- transaction --> <bean id="hibernateUtils" class="syx.zswz.util.HibernateUtils"></bean> <bean id="hibernateSessionFilter" class="syx.zswz.filter.HibernateSessionFilter"></bean>
HibernateSessionFilter.java
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; String url = req.getRequestURI();// /OA-Study/UserAction!loginUI Pattern urlPattern = Pattern.compile("\\w+!\\w+"); Matcher m = urlPattern.matcher(url); if(m.matches()) { Session session = hibernateUtils.openSession(); Transaction tx = null; try { tx = session.beginTransaction(); chain.doFilter(request, response); tx.commit(); } catch (Exception e) { if (tx != null) { tx.rollback(); } throw new RuntimeException(e); } finally { hibernateUtils.closeAndRemoveSession(); } } }
HibernateUtils.java
public class HibernateUtils { private Map<Thread, Session> sessionMap; @Resource(name="sessionFactory") SessionFactory sessionFactory; public HibernateUtils() { sessionMap = new HashMap<Thread, Session>(); } static { } /** * can only use in web filter, beause it should * remove and clear resources * @return */ public Session openSession() { System.out.println(Thread.currentThread().getStackTrace()[1] + " run in " + new Date()); Session session = sessionMap.get(Thread.currentThread()); if (session == null) { session = sessionFactory.openSession(); sessionMap.put(Thread.currentThread(), session); } return session; } public Session getCurrentSession() { return sessionMap.get(Thread.currentThread()); } public void closeAndRemoveSession() { System.out.println(Thread.currentThread().getStackTrace()[1] + " run in " + new Date());// Session session = sessionMap.remove(Thread.currentThread()); if (session != null) { session.close(); } } }
3 hibernate + struts + spring 自己处理事务
如果你们的struts使用了struts,那么所有的action请求,你使用第二种方法是拦截不到的,必须要struts2的Interceptor,在Interceptor中处理每个action的事务:
struts.xml(全局Interceptor):
<package name="admin" namespace="/admin" extends="struts-default"> <interceptors> <interceptor name="hibernateSession" class="syx.zswz.filter.HibernateSessionInterceptor"></interceptor> <interceptor-stack name="hibernateSessionStack"> <interceptor-ref name="defaultStack"></interceptor-ref> <interceptor-ref name="hibernateSession"></interceptor-ref> </interceptor-stack> </interceptors> <default-interceptor-ref name="hibernateSessionStack"></default-interceptor-ref> </package>
HibernateSessionInterceptor.java
@Override public String intercept(ActionInvocation actionIvocation) throws Exception { String retStr = null; Session session = hibernateUtils.openSession(); Transaction tx = null; try { tx = session.beginTransaction(); retStr = actionIvocation.invoke(); tx.commit(); } catch (Exception e) { if (tx != null) { tx.rollback(); } throw new RuntimeException(e); } finally { hibernateUtils.closeAndRemoveSession(); } return retStr; }
这样每一个struts的action请求过来,就会打开一个session,而请求结束时自动的提交,类似于request级别的session,而且懒加载问题应该也不会有了,因为session还没有commit,这样对于事务处理不是很强的系统可以考虑,当然对于那种事务处理控制很精细可能还要使用spring的事务处理了。
注:突然想到了为什么我用spirng事务处理的时候transaction不是很好控制的原因了,可能是:因为我把transaction都是加在service和serviceimpl层和底层的daobase上,而我的action调用service层中方法,可能调用几个方法A、B、C等,类似这种:
XXAction extends ActionSupport {
public String add() {
serviceA.get();
serviceA.update();
serviceB.save(XX);
}
}
当我第一个serviceA.get()调用完后,transaction提交,session结束,我serviceA.update()如果在用第一个方法返回的结果,可能会产生意想不到的结果,比如“一个集合不能被2个session处理”异常,我应该把transaction放到Action的方法,这样add方法进入之前打开,add出去关闭,应该是我想要的结果。时间紧,只有等下个项目测试了。