`
xiongzhenhui
  • 浏览: 205653 次
  • 性别: Icon_minigender_1
  • 来自: 厦门
社区版块
存档分类
最新评论

spring声明式事务

阅读更多

 

本文基于SPRING2.56,HIBERANTE3.25及Oracle10g classes14.jar驱动,介绍SPRING与HIBERNATE是如何配合的细节,如SESSION、 事务、数据库连接何时打开与关闭;如果调用不是发自请求,不经过FILTER(如定时器对SERVICE调用),如何做到从头到尾只用一个SESSION? 此时SESSION需不需要手动关闭?从SESSION取得的数据库连接需不需要关闭,  看完本文,你会清楚里面每一个细节。 
两种访问系统的路径: 
1、request-->filters(spring and struts)-->actions-->AOP(transaction)-->services-->dao-->db 
2、timer(run)->AOP(transaction)-->services-->dao-->db 
    下面是调用链的图示 

 

在WEB.XML配置了OpenSessionInViewFilter,整个请求只用一个SESSION, 
在ACTION与SERVICE之间使用SPRING的AOP配置事务拦截器,所以事务范围涵盖整个SERVICE的方法调用, 
DAO中一般使用SPRING的HibernateTemplate对象操作数据库 
首先看OpenSessionInViewFilter在web.xml和事务拦截器相关配置


Xml代码

复制代码
  1. <!--web.xml-->  
  2. <filter>  
  3.     <filter-name>openSessionInViewFilter</filter-name>  
  4.     <filter-class>  
  5.         org.springframework.orm.hibernate3.support.OpenSessionInViewFilter  
  6.     </filter-class>  
  7.     <init-param>  
  8.         <param-name>singleSession</param-name>  
  9.         <param-value>true</param-value>  
  10.     </init-param>  
  11. </filter>  
  12.   
  13. /////SRPING配置文件中事务拦截器相关配置  
  14. <!-- hibernate 事务管理者 -->  
  15. <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
  16.     <property name="sessionFactory" ref="sessionFactory"></property>  
  17. </bean>  
  18. <!-- hibernate 事务拦截器 -->  
  19. <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">  
  20.     <!--   注入事务管理者 -->  
  21.     <property name="transactionManager" ref="transactionManager" />  
  22.     <property name="transactionAttributes">  
  23.         <!--   定义事务属性-->  
  24.         <props>  
  25.             <prop key="*">PROPAGATION_REQUIRED</prop>  
  26.             <prop key="insert*">PROPAGATION_REQUIRED</prop>  
  27.             <prop key="add*">PROPAGATION_REQUIRED</prop>  
  28.             <prop key="save*">PROPAGATION_REQUIRED</prop>  
  29.             <prop key="update*">PROPAGATION_REQUIRED</prop>  
  30.             <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>  
  31.             <prop key="search*">PROPAGATION_REQUIRED,readOnly</prop>  
  32.             <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>  
  33.             <prop key="noTran*">PROPAGATION_NOT_SUPPORTED,readOnly</prop>  
  34.         </props>  
  35.     </property>  
  36. </bean>  
  37. /////配置service自动代理  
  38. <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">  
  39.     <property name="beanNames">  
  40.         <!--   代理所有Service   -->  
  41.         <list>  
  42.             <value>*Service</value>  
  43.         </list>  
  44.     </property>  
  45.     <property name="interceptorNames">  
  46.         <list>  
  47.             <value>transactionInterceptor</value>  
  48.         </list>  
  49.     </property>  
  50. </bean>


//下面从FILTER开始分析代码
Java代码

复制代码
  1. //这是OpenSessionInViewFilter类的方法,请求到来时,此方法由父类OncePerRequestFilter的doFilter()方法调用,  
  2. protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)  
  3.         throws ServletException, IOException {  
  4.   
  5.     //取得SessionFactory实例,实际上就是调用WebApplicationContext.getBean("beanName"),  
  6.     SessionFactory sessionFactory = lookupSessionFactory(request);  
  7.     //在lookupSessionFactory方法里看到原来此FILTER还支持配置sessionFactory为的名字,默认就叫sessionFactory,如果想改成其它名字具体配置方式:  
  8.     //在web.xml中,<init-param><param-name>sessionFactoryBeanName</param-name><param-value>sessionFactory</param-value></init-param>  
  9.       
  10.     //此次调用有无打开SESSION,有的话在finally块关闭  
  11.     boolean participate = false;  
  12.     //是否单SESSION模式(上文web.xml中配置了),注意这并不意味着每个请求只用一个connection,下文详解  
  13.     if (isSingleSession()) {//这里我只分析单SESSION的情况,因为另一种情况不是此filter推荐的用法,就懒得看了  
  14.         // 单SESSION模式  
  15.           
  16.         // 是否已经打开了SESSION,一般来说每个请求一开始是没有打开的,除非在打开SESSION之后进行forward跳转并再次被拦截  
  17.         if (TransactionSynchronizationManager.hasResource(sessionFactory)) {  
  18.             participate = true;  
  19.         }  
  20.         else {  
  21.             logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");  
  22.             //打开session,注意想在整个请求内部都用SESSION,这一句还不够,还必须有下面一句。getSession方法如何打开SESSION接下来讲解  
  23.             Session session = getSession(sessionFactory);  
  24.             //把SESSION放入SessionHolder,再用sessionFactory作为KEY,SessionHolder作为VALUE放入MAP,再把此MAP放入ThreadLocal  
  25.             //------不熟ThreadLocal看这,其他人跳过,ThreadLocal有两个主要的方法,get()和set(value),用法和MAP差不多,只是不需要提供KEY,  
  26.             //KEY就是当前线程,这样对于每个线程,只能往ThreadLocal里放入一个对象,在此放入了一个MAP。  
  27.             //不同的线程可以同时操作这个ThreadLocal对象,放入内容,因为各自有着不同的KEY------//  
  28.             TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));  
  29.         }  
  30.     }  
  31.     else {//非单Session模式,本文不讨论此情况  
  32.         // deferred close mode  
  33.         if (SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) {  
  34.             // Do not modify deferred close: just set the participate flag.  
  35.             participate = true;  
  36.         }else {  
  37.             SessionFactoryUtils.initDeferredClose(sessionFactory);  
  38.         }  
  39.     }  
  40.   
  41.     try {//SESSION已打开,往下调用,-->action-->aop-->service-->dao-->db  
  42.         filterChain.doFilter(request, response);  
  43.     }  
  44.   
  45.     finally {//目标调用完成,关闭SESSION  
  46.         if (!participate) {//如果上文打开了SESSION  
  47.             if (isSingleSession()) {  
  48.                 //从ThreadLocal里面把上面放入的MAP移除  
  49.                 SessionHolder sessionHolder =  
  50.                         (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);  
  51.                 logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");  
  52.                 //关闭SESSION  
  53.                 closeSession(sessionHolder.getSession(), sessionFactory);  
  54.             }  
  55.             else {  
  56.                 // deferred close mode  
  57.                 SessionFactoryUtils.processDeferredClose(sessionFactory);  
  58.             }  
  59.         }  
  60.     }  
  61. }


getSession方法
Java代码

复制代码
  1. //OpenSessionInViewFilter类,还是上面那个FILTER类  
  2. protected Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {  
  3.     //取SESSION,下文讲解  
  4.     Session session = SessionFactoryUtils.getSession(sessionFactory, true);  
  5.     //设置提交方式,getFlushMode默认返回FlushMode.NEVER,  
  6.     //NEVER看名字好像是永不提交,其实是外部显式调用FLUSH时才提交的意思,也许是因为名字不好,此变量已过时了,新的名字是FlushMode.MANUAL  
  7.     //如果请求是写操作,会在打开事务时被改成AUTO,  
  8.     FlushMode flushMode = getFlushMode();  
  9.     if (flushMode != null) {  
  10.         session.setFlushMode(flushMode);  
  11.     }  
  12.     return session;  
  13. }


SessionFactoryUtils.doGetSession方法

Java代码

复制代码
  1. //SessionFactoryUtils类,取SESSION,此工具方法在以下两种情况被调用:在FILTER层开SESSION和在DAO层取SESSION去查数据库  
  2. //在FILTER层调用时,没有事务(执行此方法的后半部份),在DAO层调用时,由于经过了AOP,开启了事务(执行方法的前半部份)  
  3. //在没有JTA事务的环境中,此方法只是打开或取得一个SESSION,关于事务的事什么也没有做。  
  4. private static Session doGetSession(  
  5.         SessionFactory sessionFactory, Interceptor entityInterceptor,  
  6.         SQLExceptionTranslator jdbcExceptionTranslator, boolean allowCreate)  
  7.         throws HibernateException, IllegalStateException {  
  8.   
  9.     Assert.notNull(sessionFactory, "No SessionFactory specified");  
  10.     //上文放入的sessionHolder在这里被取出来,如果调用来源于FILTER,则还没有放入,取出空,如果DAO层的调用,那么就不为空了  
  11.     SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);  
  12.     ///--------------前半部份-------------------//////////////  
  13.     if (sessionHolder != null && !sessionHolder.isEmpty()) {// DAO中的调用,取得非空值,  
  14.         Session session = null;  
  15.           
  16.         //如果:事务是否已开始 && sessionHolder中没有SESSION或只有一个默认SESSION  
  17.         if (TransactionSynchronizationManager.isSynchronizationActive() &&  
  18.                 sessionHolder.doesNotHoldNonDefaultSession()) {  
  19.             //取出SESSION,里面主要判断一下SESSION有没有被关闭  
  20.             session = sessionHolder.getValidatedSession();  
  21.             //session不为空 && 事务没有开始,  
  22.             if (session != null && !sessionHolder.isSynchronizedWithTransaction()) {  
  23.                 //在AOP中开始事务时,会将这个标志设为真,所以这里不会被执行,至少我还没有发现哪一次执行经过这里了  
  24.                 logger.debug("Registering Spring transaction synchronization for existing Hibernate Session");  
  25.                 TransactionSynchronizationManager.registerSynchronization(//注册一个SESSION  
  26.                         new SpringSessionSynchronization(sessionHolder, sessionFactory, jdbcExceptionTranslator, false));  
  27.                 sessionHolder.setSynchronizedWithTransaction(true);  
  28.                 // 取出当前SESSION的提交方式  
  29.                 FlushMode flushMode = session.getFlushMode();  
  30.                 if (flushMode.lessThan(FlushMode.COMMIT) &&  
  31.                         !TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {  
  32.                     //如果是小于COMMIT,就是NEVER,那么改成自动  
  33.                     session.setFlushMode(FlushMode.AUTO);  
  34.                     //设置之前的提交模式  
  35.                     sessionHolder.setPreviousFlushMode(flushMode);  
  36.                 }  
  37.             }  
  38.         }  
  39.         else {//这里也是一般都不会被执行,因为AOP中已经开启了事务  
  40.             // No Spring transaction management active -> try JTA transaction synchronization.  
  41.             session = getJtaSynchronizedSession(sessionHolder, sessionFactory, jdbcExceptionTranslator);  
  42.         }  
  43.         if (session != null) {  
  44.             return session;  
  45.         }  
  46.     }  
  47.     ////////-------------------后半部份--------------------------  
  48.       
  49.     //来自FILTER的调用,一般sessionHolder为空(同一请求forward后被再次拦截就不会空,执行不到这里),  
  50.     logger.debug("Opening Hibernate Session");  
  51.     //调用HIBERNATE打开SESSION  
  52.     Session session = (entityInterceptor != null ?  
  53.             sessionFactory.openSession(entityInterceptor) : sessionFactory.openSession());  
  54.   
  55.     // 当前请求是否已开启事务,FILTER中的调用,还没有到AOP层,事务没有打开,一般会执行ELSE  
  56.     if (TransactionSynchronizationManager.isSynchronizationActive()) {  
  57.         // We're within a Spring-managed transaction, possibly from JtaTransactionManager.  
  58.         logger.debug("Registering Spring transaction synchronization for new Hibernate Session");  
  59.         SessionHolder holderToUse = sessionHolder;  
  60.         if (holderToUse == null) {  
  61.             holderToUse = new SessionHolder(session);  
  62.         }  
  63.         else {  
  64.             holderToUse.addSession(session);  
  65.         }  
  66.         if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {  
  67.             session.setFlushMode(FlushMode.NEVER);  
  68.         }  
  69.         TransactionSynchronizationManager.registerSynchronization(  
  70.                 new SpringSessionSynchronization(holderToUse, sessionFactory, jdbcExceptionTranslator, true));  
  71.         holderToUse.setSynchronizedWithTransaction(true);  
  72.         if (holderToUse != sessionHolder) {  
  73.             TransactionSynchronizationManager.bindResource(sessionFactory, holderToUse);  
  74.         }  
  75.     }  
  76.     else {  
  77.         // 上面没有找到事务,从sessionFactory中找,如果sessionFactory有配置JTA事务,则注册事务  
  78.         // 本文也没有配置JTA事务,所以里面什么也没有干,还是没有注册事务  
  79.         registerJtaSynchronization(session, sessionFactory, jdbcExceptionTranslator, sessionHolder);  
  80.     }  
  81.   
  82.     // 如果不自动创建 && sessionHolder中没有session,则关闭SESSION  
  83.     if (!allowCreate && !isSessionTransactional(session, sessionFactory)) {  
  84.         closeSession(session);  
  85.         throw new IllegalStateException("No Hibernate Session bound to thread, " +  
  86.             "and configuration does not allow creation of non-transactional one here");  
  87.     }  
  88.     //到此就在FILTER中取得了(或者说打开了)SESSION,下面就从ACTION调用SERVICE这一节了。  
  89.     return session;  
  90. }


//下面开始到了ACTION的操作,action调用service,此service实际上是Spring动态生成的代理类,此代理类调用
//目标SERVICE类对应的方法前,要经过AOP拦截,下面我们对ACTION到SERVICE这中间经过的所有类方法代码分析一遍。
//我的应用在AOP层配置了一个事务拦截器,所以这中间的代码主要操作事务相关。
//动态生成的代理类代码看不到,从动态代理类下面的那个类(JdkDynamicAopProxy)开始吧

Java代码

复制代码
  1. //JdkDynamicAopProxy类,此方法被动态代理类调用  
  2. //参数说明:proxy动态代理类对象,method目标方法,args目标方法参数  
  3. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  4.     MethodInvocation invocation = null;  
  5.     Object oldProxy = null;  
  6.     boolean setProxyContext = false;  
  7.   
  8.     //targetSource对象包含目标SERVICE对象  
  9.     TargetSource targetSource = this.advised.targetSource;  
  10.     Class targetClass = null;  
  11.     Object target = null;  
  12.   
  13.     try {  
  14.         //如果目标类没有重载equals方法 && 目前正在调用目标类的equals方法,那直接调本类重载方法,  
  15.         //这样就不需要再往下走,不需要再开启事务等等多余的操作以至于浪费性能了,下面的几个IF都是做类似的事  
  16.         if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {  
  17.             // The target does not implement the equals(Object) method itself.  
  18.             return (equals(args[0]) ? Boolean.TRUE : Boolean.FALSE);  
  19.         }  
  20.         if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {  
  21.             // The target does not implement the hashCode() method itself.  
  22.             return new Integer(hashCode());  
  23.         }  
  24.         if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&  
  25.                 method.getDeclaringClass().isAssignableFrom(Advised.class)) {  
  26.             // Service invocations on ProxyConfig with the proxy config...  
  27.             return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);  
  28.         }  
  29.   
  30.         Object retVal = null;  
  31.   
  32.         //ProxyConfig类的exposeProxy属性,表示是否要将当前的代理对象放入AopContext中,  
  33.         //这样在你的Service中可以用AopContext.currentProxy()取得当前代理,相当于this引用,  
  34.         //不同于this引用的是,调用当前代理会被AOP拦截,而this不会。  
  35.         //此属性默认为FALSE,如果要打开,  
  36.         //在BeanNameAutoProxyCreator等代理类BEAN的配置中加入<property name="exposeProxy" value="true" />  
  37.         if (this.advised.exposeProxy) {  
  38.             // Make invocation available if necessary.  
  39.             oldProxy = AopContext.setCurrentProxy(proxy);  
  40.             setProxyContext = true;  
  41.         }  
  42.   
  43.         // 取得目标(真实SERVICE对象)  
  44.         target = targetSource.getTarget();  
  45.         if (target != null) {  
  46.             targetClass = target.getClass();  
  47.         }  
  48.   
  49.         // 取得所有拦截器  
  50.         List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);  
  51.   
  52.         // 如果没有拦截器  
  53.         if (chain.isEmpty()) {  
  54.             // 直接调用目标  
  55.             retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);  
  56.         }  
  57.         else {//有拦截器  
  58.             // 创建一个调用器对象  
  59.             invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);  
  60.             // 通过调用器往下调用目标或第一个拦截器  
  61.             retVal = invocation.proceed();  
  62.         }  
  63.   
  64.         // 调用的返回结果目标类对象本身,就把它替换成代理类对象  
  65.         if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy) &&  
  66.                 !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {  
  67.             retVal = proxy;  
  68.         }  
  69.         return retVal;  
  70.     }  
  71.     finally {//释放资源  
  72.         //主要是从当前线程清除代理类对象  
  73.         if (target != null && !targetSource.isStatic()) {  
  74.             targetSource.releaseTarget(target);  
  75.         }  
  76.         if (setProxyContext) {  
  77.             // Restore old proxy.  
  78.             AopContext.setCurrentProxy(oldProxy);  
  79.         }  
  80.     }  
  81. }


递归调用拦截器

Java代码

复制代码
  1. //ReflectiveMethodInvocation类,上面执行retVal = invocation.proceed();就进入到了这个方法  
  2. //这个方法主要是递归调用各个拦截器,最后调用目标类  
  3. public Object proceed() throws Throwable {  
  4.     //  判断是否还有拦截器要调用,  
  5.     if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {  
  6.         //没有拦截器了,调用目标  
  7.         return invokeJoinpoint();  
  8.     }  
  9.   
  10.     //取出拦截器  
  11.     Object interceptorOrInterceptionAdvice =  
  12.         this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);  
  13.       
  14.     //判断拦截器型,对不同类型的调用方法不一样,SPRING事务拦截器TransactionInterceptor是MethodInterceptor实现类,  
  15.     //不属于InterceptorAndDynamicMethodMatcher,执行ELSE  
  16.     if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {  
  17.         InterceptorAndDynamicMethodMatcher dm =  
  18.             (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;  
  19.         if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {  
  20.             return dm.interceptor.invoke(this);  
  21.         }  
  22.         else {//方法匹配失败,跳过,继续递归  
  23.             return proceed();  
  24.         }  
  25.     }  
  26.     else {  
  27.         // 调用事务拦截器等,MethodInterceptor--林信良的SPRING手册介绍过个这接口如何使用  
  28.         return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);  
  29.     }  
  30. }


事务拦截器

Java代码

复制代码
  1. //TransactionInterceptor--SPRING的事务拦截器实现类,这个方法可以根据事务管理器的种类分类if和else上下两部分,  
  2. //如果配置的是org.springframework.orm.hibernate3.HibernateTransactionManager等非CallbackPreferringPlatformTransactionManager接口实现类  
  3. //则看只需要看if部份  
  4. //了解这里工作原理很重要:  
  5. //1、如果是请求发起的调用,流程路线为--FILTER打开Session,并且绑定到了线程信息中(TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session))),  
  6. //在此方法里标志为旧SESSION,开始事务,调用目标,提交或回滚事务,判断如果是旧SESSION,则事务结束释放连接但不关闭SESSION,如果还用此SESSION再开启事务,再绑定另外的连接(所以上文说单SESSION并不等于同一个连接),最后在FILTER关闭SESSION。  
  7. //2、如果不是请求发起的调用,如计划任务Timer.schedule(...)发起的SERVICE调用,流程为--在此方法打开SESSION,标志为新连接,开启事务,调用目标,提交或回滚事务,释放数据库连接,判断如果是新SESSION,则关闭SESSION。  
  8. //总结如下:  
  9. //1、只要有配置了此事务拦截器,底层使用SPRING的HibernateTemplate.getSession()或其提供的各种查询,那么SESSION和数据库连接的关闭不需要你操心。  
  10. //2、如果要在Timer的run方法中多次调用SERVICE时,也要实现OpenSessionInViewFilter这样的效果,那么使用如这句,结束时要记得自已关闭SESSION。  
  11. //打开SESSION后:TransactionSynchronizationManager.bindResource(getSessionFactory(), new SessionHolder(session));  
  12. //最后关闭SESSION:  
  13. //SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.unbindResource(getSessionFactory());  
  14. //SessionFactoryUtils.closeSession(sessionHolder.getSession());  
  15. public Object invoke(final MethodInvocation invocation) throws Throwable {  
  16.     // 取得目标类名  
  17.     Class targetClass = (invocation.getThis() != null ? invocation.getThis().getClass() : null);  
  18.   
  19.     // 通过类名及方法名,取得事务属性,即<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>这些内容  
  20.     final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass);  
  21.     //取得类名+方法名全称  
  22.     final String joinpointIdentification = methodIdentification(invocation.getMethod());  
  23.     //没有事务属性 || 事务管理者不是CallbackPreferringPlatformTransactionManager类型(事务采用回调方法实现的方式)  
  24.     if (txAttr == null || !(getTransactionManager() instanceof CallbackPreferringPlatformTransactionManager)) {  
  25.         //开始事务并创建事务信息对象(此对象主要包括事务属性和事务状态等信息),就是在这里调用了session.beginTransaction()方法  
  26.         //将事务信息以当前线程为KEY放入了TransactionAspectSupport.transactionInfoHolder对象中  
  27.         //注意:到这里如果当前取得到SessionHolder,那么SESSION就被标记成老SESSION,提交事务时就不会关闭之,反之那么session会在打开,并被标为新SESSION,提交事务时会把此SESSION关闭  
  28.         TransactionInfo txInfo = createTransactionIfNecessary(txAttr, joinpointIdentification);  
  29.         Object retVal = null;  
  30.         try {  
  31.             // 调用下一下拦截器,如果没有下一个拦截器,那么目标类会被调用  
  32.             retVal = invocation.proceed();  
  33.         }  
  34.         catch (Throwable ex) {  
  35.             // 发生异常时,在这里回滚,回滚时,除了rollBack,还执行session.clear(),setFlushMode(NEVER)等动作  
  36.             // 新SESSION会在此被关闭,老的则不会  
  37.             completeTransactionAfterThrowing(txInfo, ex);  
  38.             throw ex;  
  39.         }  
  40.         finally {  
  41.             //清理当前线程对应的事务信息,  
  42.             cleanupTransactionInfo(txInfo);  
  43.         }  
  44.         //未发生异常,提交事务,如果是新SESSION,会在此被关闭,老的则不会  
  45.         commitTransactionAfterReturning(txInfo);  
  46.         return retVal;  
  47.     }  
  48.   
  49.     else {  
  50.         // 回调式的事务管理器,SPRING中只提供了一个WebSphereUowTransactionManager的具体实现,  
  51.         /**CallbackPreferringPlatformTransactionManager接口的注释
  52.          * Extension of the {@link org.springframework.transaction.PlatformTransactionManager}
  53.          * interface, exposing a method for executing a given callback within a transaction.
  54.          * <p>Implementors of this interface automatically express a preference for
  55.          * callbacks over programmatic <code>getTransaction</code>, <code>commit</code>
  56.          * and <code>rollback</code> calls. Calling code may check whether a given
  57.          * transaction manager implements this interface to choose to prepare a
  58.          * callback instead of explicit transaction demarcation control.*/  
  59.         // 大意应该是可以由此接口的具体实现来决定事务的控制,我的E文一般般,有错的就砸砖  
  60.         try {  
  61.             Object result = ((CallbackPreferringPlatformTransactionManager) getTransactionManager()).execute(txAttr,  
  62.                     new TransactionCallback() {  
  63.                         public Object doInTransaction(TransactionStatus status) {  
  64.                             TransactionInfo txInfo = prepareTransactionInfo(txAttr, joinpointIdentification, status);  
  65.                             try {  
  66.                                 //往下调用  
  67.                                 return invocation.proceed();  
  68.                             }  
  69.                             catch (Throwable ex) {  
  70.                                 if (txAttr.rollbackOn(ex)) {  
  71.                                     // A RuntimeException: will lead to a rollback.  
  72.                                     if (ex instanceof RuntimeException) {  
  73.                                         throw (RuntimeException) ex;  
  74.                                     }  
  75.                                     else {  
  76.                                         throw new ThrowableHolderException(ex);  
  77.                                     }  
  78.                                 }  
  79.                                 else {  
  80.                                     // A normal return value: will lead to a commit.  
  81.                                     return new ThrowableHolder(ex);  
  82.                                 }  
  83.                             }  
  84.                             finally {  
  85.                                 cleanupTransactionInfo(txInfo);  
  86.                             }  
  87.                         }  
  88.                     });  
  89.   
  90.             // Check result: It might indicate a Throwable to rethrow.  
  91.             if (result instanceof ThrowableHolder) {  
  92.                 throw ((ThrowableHolder) result).getThrowable();  
  93.             }  
  94.             else {  
  95.                 return result;  
  96.             }  
  97.         }  
  98.         catch (ThrowableHolderException ex) {  
  99.             throw ex.getCause();  
  100.         }  
  101.     }  
  102. }

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics