类内部调用的事务回滚

什么是内部调用的事务

什么是内部调用的事务呢,我们先来看一段内部调用事务的代码

public class XX {

    public void testA() {
        testB();
    }

    @Transactional
    public void testB() {
        ...
    }

}

相信你已经看完了,下面有几个小问题:

1.以上代码能回滚吗 ?

2.stream中调用是否能回滚 ?

3.多线程如parallelStream中调用是否能回滚 ?

那就继续往下看吧…

如何实现类内部调用事务回滚

以上代码是不能回滚的,因为spring中的调用反射都是基于类的拦截,而方法层面的调用时无法拦截的,所以无法使@Transactional注解生效。
下面提供两种方法可以让这种内部方法调用的事务生效。

方法一

使用AopContext.currentProxy实现AOP代理。

// 开启AOP,为让AopContext.currentProxy()生效
@EnableAspectJAutoProxy(exposeProxy = true)

class xxx {

    public void test() {
        ...
        // 如果是多线程调用,currentProxy这句话要写在线程调用外,因为子线程无法获取主线程的代理类
        XXService proxy = (XXService) AopContext.currentProxy();
        proxy.testCalledMethod(param1, param2);
        ...
    }

    // 此处需为public
    @Transactional(rollbackFor = Throwable.class)
    public void testCalledMethod() {...}

}

@Async和@Transactional一起用报错的解决方案,源自一篇很好的文章:https://cloud.tencent.com/developer/article/1497700,有兴趣的同学可以看看。

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {


    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition beanDefinition =
                beanFactory.getBeanDefinition(TaskManagementConfigUtils.ASYNC_EXECUTION_ASPECT_BEAN_NAME);
        beanDefinition.getPropertyValues().add("exposeProxy", true);
    }
}

方法二

使用Callable的方式写一个代理服务类,所有的类内部调用都通过代理类实现。这样的方式直接通过类调用@Transaction注解的方法,也可以支持多线程。
被调用的事务方法也无需像方法一要声明成public,也无需加@Transactional注解,因为都是走的代理类的注解。

@Component
public class ProxyService {

    /**
     * 调用此方法实现事务
     * @throws Exception
     */
    @Transactional(rollbackFor = Throwable.class)
    public <T> T executeTransactionProxy(Callable<T> callable) throws Throwable {
        return callable.call();
    }

}

回滚源码分析

下面分析下方法一的流程,方法二的流程区别就是所有的拦截都是走代理类,其他都一样,因为AopContext.currentProxy的作用就是将我们的内部调用的方法也变成可拦截的。
以下是调用AopContext.currentProxy开始往后走的流程。

这里是流程上涉及到的一些类,可能没有列全,不过可以看出大概结构。
在这里插入图片描述

CglibAopProxy

实现了spring框架的Aop静态代理,实现了AopProxy接口,同样实现了此接口的还有JdkDynamicAopProxy(Jdk动态代理)。

DynamicAdvisedInterceptor是CglibAopProxy的内部类

/**
	 * General purpose AOP callback. Used when the target is dynamic or when the
	 * proxy is not frozen.
	 */
	private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {

		private final AdvisedSupport advised;

		public DynamicAdvisedInterceptor(AdvisedSupport advised) {
			this.advised = advised;
		}

		@Override
		public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
			Object oldProxy = null;
			boolean setProxyContext = false;
			Class<?> targetClass = null;
			Object target = null;
			try {
				if (this.advised.exposeProxy) {
					// Make invocation available if necessary.
					oldProxy = AopContext.setCurrentProxy(proxy);
					setProxyContext = true;
				}
				// May be null. Get as late as possible to minimize the time we
				// "own" the target, in case it comes from a pool...
				target = getTarget();
				if (target != null) {
					targetClass = target.getClass();
				}
				List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
				Object retVal;
				// 如果无拦截器,并且反射方法是Public的,则直接invoke
				// Check whether we only have one InvokerInterceptor: that is,
				// no real advice, but just reflective invocation of the target.
				if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
					// We can skip creating a MethodInvocation: just invoke the target directly.
					// Note that the final invoker must be an InvokerInterceptor, so we know
					// it does nothing but a reflective operation on the target, and no hot
					// swapping or fancy proxying.
					Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
					retVal = methodProxy.invoke(target, argsToUse);
				}
				else {
					// 创建方法反射类
					// We need to create a method invocation...
					retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
				}
				retVal = processReturnType(proxy, target, method, retVal);
				return retVal;
			}
			finally {
				if (target != null) {
					releaseTarget(target);
				}
				if (setProxyContext) {
					// Restore old proxy.
					AopContext.setCurrentProxy(oldProxy);
				}
			}
		}

ReflectiveMethodInvocation–>proceed
CglibMethodInvocation是CglibAopProxy的内部类。
testCalledMethod及其内部调用的方法都会通过上面的类,再调用
CglibMethodInvocation.proceed(ReflectiveMethodInvocation的子类),这其实就是AOP的方法反射过程。

public Object proceed() throws Throwable {
	// 如拦截器已全部被调用,则直接调用invoke
   // We start with an index of -1 and increment early.
   if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
      return invokeJoinpoint();
   }

	// 调用当前拦截器的invoke
   Object interceptorOrInterceptionAdvice =
         this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
   if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
      // Evaluate dynamic method matcher here: static part will already have
      // been evaluated and found to match.
      InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
      if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
         return dm.interceptor.invoke(this);
      }
      else {
         // Dynamic matching failed.
         // Skip this interceptor and invoke the next in the chain.
         return proceed();
      }
   }
   else {
      // It's an interceptor, so we just invoke it: The pointcut will have
      // been evaluated statically before this object was constructed.
      // 事务拦截器会走这里
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
}

TransactionInterceptor–>invoke

走到事务拦截器中

public Object invoke(final MethodInvocation invocation) throws Throwable {
   // Work out the target class: may be {@code null}.
   // The TransactionAttributeSource should be passed the target class
   // as well as the method, which may be from an interface.
   Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

   // 适配器模式,执行TransactionAspectSupport模板方法invokeWithinTransaction,并且回调函数重写方法proceedWithInvocation进行具体的方法反射执行
   // Adapt to TransactionAspectSupport's invokeWithinTransaction...
   return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
      @Override
      public Object proceedWithInvocation() throws Throwable {
         return invocation.proceed();
      }
   });
}

TransactionInterceptor的父类TransactionAspectSupport–>invokeWithinTransaction
具体可参考:https://www.cnblogs.com/chihirotan/p/6739748.html

protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
      throws Throwable {


   // If the transaction attribute is null, the method is non-transactional.
    // 获取事务属性(包括@transactional注解上的属性,有:事务的隔离级别和传播行为,事务超时时间,事务是否只读,事务的名称)
   final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
   final PlatformTransactionManager tm = determineTransactionManager(txAttr);
   final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);


   if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
      // Standard transaction demarcation with getTransaction and commit/rollback calls.
      TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
      Object retVal = null;
      try {
         // This is an around advice: Invoke the next interceptor in the chain.
         // This will normally result in a target object being invoked.
         retVal = invocation.proceedWithInvocation();
      }
      catch (Throwable ex) {
         // target invocation exception
         // 异常回滚
         completeTransactionAfterThrowing(txInfo, ex);
         throw ex;
      }
      finally {
         cleanupTransactionInfo(txInfo);
      }
      commitTransactionAfterReturning(txInfo);
      return retVal;
   }


   else {
      final ThrowableHolder throwableHolder = new ThrowableHolder();

	// 如果是编程式事务,则直接调用事务对象的execute
      // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
      try {
         Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
               new TransactionCallback<Object>() {
                  @Override
                  public Object doInTransaction(TransactionStatus status) {
                     TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
                     try {
                        return invocation.proceedWithInvocation();
                     }
                     catch (Throwable ex) {
                        if (txAttr.rollbackOn(ex)) {
                           // A RuntimeException: will lead to a rollback.
                           if (ex instanceof RuntimeException) {
                              throw (RuntimeException) ex;
                           }
                           else {
                              throw new ThrowableHolderException(ex);
                           }
                        }
                        else {
                           // A normal return value: will lead to a commit.
                           throwableHolder.throwable = ex;
                           return null;
                        }
                     }
                     finally {
                        cleanupTransactionInfo(txInfo);
                     }
                  }
               });


         // Check result state: It might indicate a Throwable to rethrow.
         if (throwableHolder.throwable != null) {
            throw throwableHolder.throwable;
         }
         return result;
      }
      catch (ThrowableHolderException ex) {
         throw ex.getCause();
      }
      catch (TransactionSystemException ex2) {
         if (throwableHolder.throwable != null) {
            logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
            ex2.initApplicationException(throwableHolder.throwable);
         }
         throw ex2;
      }
      catch (Throwable ex2) {
         if (throwableHolder.throwable != null) {
            logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
         }
         throw ex2;
      }
   }
}

上面异常回滚的方法

protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) {
   if (txInfo != null && txInfo.hasTransaction()) {
      if (logger.isTraceEnabled()) {
         logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
               "] after exception: " + ex);
      }
      // 是否回滚次此次抛出的异常,只要事务属性满足条件即可回滚
      if (txInfo.transactionAttribute.rollbackOn(ex)) {
         try {
            txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
         }
         catch (TransactionSystemException ex2) {
            logger.error("Application exception overridden by rollback exception", ex);
            ex2.initApplicationException(ex);
            throw ex2;
         }
         catch (RuntimeException ex2) {
            logger.error("Application exception overridden by rollback exception", ex);
            throw ex2;
         }
         catch (Error err) {
            logger.error("Application exception overridden by rollback error", ex);
            throw err;
         }
      }
      else {
         // 不回滚则在出现异常后直接commit此次事务
         // We don't roll back on this exception.
         // Will still roll back if TransactionStatus.isRollbackOnly() is true.
         try {
            txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
         }
         catch (TransactionSystemException ex2) {
            logger.error("Application exception overridden by commit exception", ex);
            ex2.initApplicationException(ex);
            throw ex2;
         }
         catch (RuntimeException ex2) {
            logger.error("Application exception overridden by commit exception", ex);
            throw ex2;
         }
         catch (Error err) {
            logger.error("Application exception overridden by commit error", ex);
            throw err;
         }
      }
   }
}

DelegatingTransactionAttribute
事务属性委托类(RuleBasedTransactionAttribute的子类):调用子类判断是否可回滚

public boolean rollbackOn(Throwable ex) {
   return this.targetAttribute.rollbackOn(ex);
}

RuleBasedTransactionAttribute 基于规则的事务属性类:判断是否可回滚

public boolean rollbackOn(Throwable ex) {
   if (logger.isTraceEnabled()) {
      logger.trace("Applying rules to determine whether transaction should rollback on " + ex);
   }


   RollbackRuleAttribute winner = null;
   int deepest = Integer.MAX_VALUE;


   // 匹配rollbackFor的规则,存在规则的话就按定义的规则进行判断
   if (this.rollbackRules != null) {
      for (RollbackRuleAttribute rule : this.rollbackRules) {
         int depth = rule.getDepth(ex);
         if (depth >= 0 && depth < deepest) {
            deepest = depth;
            winner = rule;
         }
      }
   }


   if (logger.isTraceEnabled()) {
      logger.trace("Winning rollback rule is: " + winner);
   }


   // User superclass behavior (rollback on unchecked) if no rule matches.
   // 如果没有设规则或者规则都不匹配,就执行父类DefaultTransactionAttribute的rollbackOn方法
   if (winner == null) {
      logger.trace("No relevant rollback rule found: applying default rules");
      return super.rollbackOn(ex);
   }


   return !(winner instanceof NoRollbackRuleAttribute);
}

DefaultTransactionAttribute
上面的RuleBasedTransactionAttribute的规则匹配未通过,就执行其父类DefaultTransactionAttribute的rollbackOn方法。
可以看出默认支持的异常类型是RuntimeException和Error,就是说如果我们没有指定rollbackFor=以Exception为父类的异常类,那么我们要是抛出以Exception为父类的异常是不会回滚的。

public boolean rollbackOn(Throwable ex) {
   return (ex instanceof RuntimeException || ex instanceof Error);
}

RollbackRuleAttribute–>getDepth
递归查询当前类及其父类,异常类名匹配则返回递归深度,即匹配rollback规则指定异常类在我们所抛出异常类的深度。
这里看来,所以我们在代码中抛出的异常必须是我们指定rollbackFor的异常的子类。

public int getDepth(Throwable ex) {
   return getDepth(ex.getClass(), 0);
}

private int getDepth(Class<?> exceptionClass, int depth) {
   if (exceptionClass.getName().contains(this.exceptionName)) {
      // Found it!
      return depth;
   }
   // If we've gone as far as we can go and haven't found it...
   if (exceptionClass == Throwable.class) {
      return -1;
   }
   return getDepth(exceptionClass.getSuperclass(), depth + 1);
}

AnnotationTransactionAttributeSource 获取注解中的事务属性值
上面代码调用了其父类AbstractFallbackTransactionAttributeSource中的getTransactionAttribute方法

public TransactionAttribute getTransactionAttribute(Method method, Class<?> targetClass) {
   if (method.getDeclaringClass() == Object.class) {
      return null;
   }

   // 首先从缓存中获取事务属性,没有的话再从方法注解上获取
   // First, see if we have a cached value.
   Object cacheKey = getCacheKey(method, targetClass);
   Object cached = this.attributeCache.get(cacheKey);
   if (cached != null) {
      // Value will either be canonical value indicating there is no transaction attribute,
      // or an actual transaction attribute.
      if (cached == NULL_TRANSACTION_ATTRIBUTE) {
         return null;
      }
      else {
         return (TransactionAttribute) cached;
      }
   }
   else {
      // 下面逻辑是先从方法注解中获取事务属性,然后存入属性缓存(attributeCache)中
      // We need to work it out.
      TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
      // Put it in the cache.
      if (txAttr == null) {
         this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
      }
      else {
         String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
         if (txAttr instanceof DefaultTransactionAttribute) {
            ((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
         }
         if (logger.isDebugEnabled()) {
            logger.debug("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
         }
         this.attributeCache.put(cacheKey, txAttr);
      }
      return txAttr;
   }
}

protected TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) {
   // 非public的方法事务注解失效
   // Don't allow no-public methods as required.
   if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
      return null;
   }


   // Ignore CGLIB subclasses - introspect the actual user class.
   Class<?> userClass = ClassUtils.getUserClass(targetClass);
   // The method may be on an interface, but we need attributes from the target class.
   // If the target class is null, the method will be unchanged.
   // 找出代理的真实方法
   Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
   // If we are dealing with method with generic parameters, find the original method.
   // 确保specificMethod不是生成的桥接方法
   specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);

   // 首先会检测目标类中的方法上的Transactional注解
   // First try is the method in the target class.
   TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
   if (txAttr != null) {
      return txAttr;
   }

   // 然后会检测目标类上的Transactional注解
   // Second try is the transaction attribute on the target class.
   txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
   if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
      return txAttr;
   }


   if (specificMethod != method) {
      // Fallback is to look at the original method.
      txAttr = findTransactionAttribute(method);
      if (txAttr != null) {
         return txAttr;
      }
      // Last fallback is the class of the original method.
      txAttr = findTransactionAttribute(method.getDeclaringClass());
      if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
         return txAttr;
      }
   }


   return null;
}

AnnotationTransactionAttributeSource(上面AbstractFallbackTransactionAttributeSource的子类)

protected TransactionAttribute findTransactionAttribute(Method method) {
   return determineTransactionAttribute(method);
}

protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
   return determineTransactionAttribute(clazz);
}

protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) {
   if (ae.getAnnotations().length > 0) {
      for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
         TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae);
         if (attr != null) {
            return attr;
         }
      }
   }
   return null;
}

SpringTransactionAnnotationParser
解析Transactional注解生成TransactionAttribute

public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
   AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class);
   if (attributes != null) {
      return parseTransactionAnnotation(attributes);
   }
   else {
      return null;
   }
}

// 可以看出解析出的事务属性类是RuleBasedTransactionAttribute,此属性类用来判断事务是否回滚
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
   RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
   Propagation propagation = attributes.getEnum("propagation");
   rbta.setPropagationBehavior(propagation.value());
   Isolation isolation = attributes.getEnum("isolation");
   rbta.setIsolationLevel(isolation.value());
   rbta.setTimeout(attributes.getNumber("timeout").intValue());
   rbta.setReadOnly(attributes.getBoolean("readOnly"));
   rbta.setQualifier(attributes.getString("value"));
   ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<RollbackRuleAttribute>();
   Class<?>[] rbf = attributes.getClassArray("rollbackFor");
   for (Class<?> rbRule : rbf) {
      RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
      rollBackRules.add(rule);
   }
   String[] rbfc = attributes.getStringArray("rollbackForClassName");
   for (String rbRule : rbfc) {
      RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
      rollBackRules.add(rule);
   }
   Class<?>[] nrbf = attributes.getClassArray("noRollbackFor");
   for (Class<?> rbRule : nrbf) {
      NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
      rollBackRules.add(rule);
   }
   String[] nrbfc = attributes.getStringArray("noRollbackForClassName");
   for (String rbRule : nrbfc) {
      NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
      rollBackRules.add(rule);
   }
   rbta.getRollbackRules().addAll(rollBackRules);
   return rbta;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值