侧边栏壁纸
博主头像
Coder 博主等级

行动起来,活在当下

  • 累计撰写 55 篇文章
  • 累计创建 1 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

04-声明式事务源码

04-声明式事务源码

# Spring-声明式事务源码

文档:声明式事务基础.note

链接:http://note.youdao.com/noteshare?id=ff37ac30b4581065a2728030534c5193&sub=13862778AEC34E07A30008F19FBF8094

Spring-声明式事务源码

@Transactional的使用

原理

事务集成过程:

解析advisor

创建动态代理

调用代理对象

顶层的事务逻辑

嵌套的事务逻辑

@Transactional的使用

SpringBoot大行其道的今天,基于XML配置的Spring Framework的使用方式注定已成为过去式。

注解驱动应用,面向元数据编程已然成受到越来越多开发者的偏好了,毕竟它的便捷程度、优势都是XML方式不可比拟的。

对SpringBoot有多了解,其实就是看你对Spring Framework有多熟悉~ 比如SpringBoot大量的模块装配的设计模式,其实它属于Spring Framework提供的能力

1、开启注解驱动


/**
 * Created by xsls on 2019/6/17.
 */
@EnableTransactionManagement
@EnableAspectJAutoProxy//(exposeProxy = true)
@ComponentScan(basePackages = {"com.tuling"})
public class MainConfig {

    @Bean
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        dataSource.setUrl("jdbc:mysql://localhost:3306/tuling-spring-trans");
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        return dataSource;
    }

    /**
     *  配置JdbcTemplate Bean组件
     *     <bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
     *         <property name="dataSource" ref="dataSource" ></property>
     *     </bean>
     * @param dataSource
     * @return
     */
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    /**
     *  配置事务管理器
     *     <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
     *         <property name="dataSource" ref="dataSource"></property>
     *     </bean>
     * @param dataSource
     * @return
     */
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

}

提示:使用@EnableTransactionManagement注解前,请务必保证你已经配置了至少一个PlatformTransactionManager的Bean,否则会报错。(当然你也可以实现TransactionManagementConfigurer来提供一个专属的,只是我们一般都不这么去做~~~)

2、在你想要加入事务的方法上(或者类(接口)上)标注@Transactional注解


@Component
@Transactional(rollbackFor = Exception.class)
public class PayServiceImpl implements PayService {

    @Autowired
    private AccountInfoDao accountInfoDao;

    @Autowired
    private ProductInfoDao productInfoDao;

    public void pay(String accountId, double money) {

        //更新余额
         int retVal = accountInfoDao.updateAccountBlance(accountId,money);

        System.out.println(1/0);

    }
}

运行测试:

public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);

    PayService payService = (PayService) context.getBean("payServiceImpl");
    payService.pay("123456789",10);

}

就这么简单,事务就生效了(这条数据并没有insert成功~)。

原理

事务集成过程:

接下来分析注解驱动事务的原理,同样的我们从@EnableTransactionManagement开始:

@EnableTransactionManagement

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
	boolean proxyTargetClass() default false;
	AdviceMode mode() default AdviceMode.PROXY;
	int order() default Ordered.LOWEST_PRECEDENCE;
}

简直不要太面熟好不好,属性和@EnableAspectJAutoProxy注解一个套路。不同之处只在于@Import导入器导入的这个类,不同的是:它导入的是个ImportSelector

TransactionManagementConfigurationSelector

它所在的包为org.springframework.transaction.annotation,jar属于:spring-tx(若引入了spring-jdbc,这个jar会自动导入)

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

	@Override
	protected String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			// 很显然,绝大部分情况下,我们都不会使用AspectJ的静态代理的~~~~~~~~
			// 这里面会导入两个类~~~
			case PROXY:
				return new String[] {AutoProxyRegistrar.class.getName(),
						ProxyTransactionManagementConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {determineTransactionAspectClass()};
			default:
				return null;
		}
	}
	private String determineTransactionAspectClass() {
		return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
				TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
				TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
	}

}

AdviceModeImportSelector目前所知的三个子类是:AsyncConfigurationSelector、TransactionManagementConfigurationSelector、CachingConfigurationSelector。由此可见后面还会着重分析的Spring的缓存体系@EnableCaching,和异步@EnableAsync模式也是和这个极其类似的~~~

AutoProxyRegistrar

从名字是意思是:自动代理注册器。它是个ImportBeanDefinitionRegistrar,可以实现自己向容器里注册Bean的定义信息

// @since 3.1
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		boolean candidateFound = false;

		// 这里面需要特别注意的是:这里是拿到所有的注解类型~~~而不是只拿@EnableAspectJAutoProxy这个类型的
		// 原因:因为mode、proxyTargetClass等属性会直接影响到代理得方式,而拥有这些属性的注解至少有:
		// @EnableTransactionManagement、@EnableAsync、@EnableCaching等~~~~
		// 甚至还有启用AOP的注解:@EnableAspectJAutoProxy它也能设置`proxyTargetClass`这个属性的值,因此也会产生关联影响~
		Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
		for (String annoType : annoTypes) {
			AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
			if (candidate == null) {
				continue;
			}
			// 拿到注解里的这两个属性
			// 说明:如果你是比如@Configuration或者别的注解的话  他们就是null了
			Object mode = candidate.get("mode");
			Object proxyTargetClass = candidate.get("proxyTargetClass");

			// 如果存在mode且存在proxyTargetClass 属性
			// 并且两个属性的class类型也是对的,才会进来此处(因此其余注解相当于都挡外面了~)
			if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
					Boolean.class == proxyTargetClass.getClass()) {

				// 标志:找到了候选的注解~~~~
				candidateFound = true;
				if (mode == AdviceMode.PROXY) {
					// 这一部是非常重要的~~~~又到了我们熟悉的AopConfigUtils工具类,且是熟悉的registerAutoProxyCreatorIfNecessary方法
					// 它主要是注册了一个`internalAutoProxyCreator`,但是若出现多次的话,这里不是覆盖的形式,而是以第一次的为主
					// 当然它内部有做等级的提升之类的,这个之前也有分析过~~~~
					AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);

					// 看要不要强制使用CGLIB的方式(由此可以发现  这个属性若出现多次,是会是覆盖的形式)
					if ((Boolean) proxyTargetClass) {
						AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
						return;
					}
				}
			}
		}

		// 如果一个都没有找到(我在想,肿么可能呢?)
		// 其实有可能:那就是自己注入这个类,而不是使用注解去注入(但并不建议这么去做)
		if (!candidateFound && logger.isInfoEnabled()) {
			// 输出info日志(注意并不是error日志)
		}
	}

}

这一步最重要的就是向Spring容器注入了一个自动代理创建器:org.springframework.aop.config.internalAutoProxyCreator,这里有个小细节注意一下,由于AOP和事务注册的都是名字为org.springframework.aop.config.internalAutoProxyCreator 的BeanPostProcessor,但是只会保留一个,AOP的会覆盖事务的, 因为AOP优先级更大

所以假如@EnableTransactionManagement和@EnableAspectJAutoProxy 同时存在, 那么AOP的 AutoProxyCreator 会进行覆盖。

ProxyTransactionManagementConfiguration

它是一个@Configuration,所以看看它向容器里注入了哪些Bean

@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	// 这个Advisor可是事务的核心内容。。。。。也是本文重点分析的对象
	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		advisor.setTransactionAttributeSource(transactionAttributeSource());
		advisor.setAdvice(transactionInterceptor());
		// 顺序由@EnableTransactionManagement注解的Order属性来指定 默认值为:Ordered.LOWEST_PRECEDENCE
		if (this.enableTx != null) {
			advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
		}
		return advisor;
	}

	// TransactionAttributeSource 这种类特别像 `TargetSource`这种类的设计模式
	// 这里直接使用的是AnnotationTransactionAttributeSource  基于注解的事务属性源~~~
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}

	// 事务拦截器,它是个`MethodInterceptor`,它也是Spring处理事务最为核心的部分
	// 请注意:你可以自己定义一个TransactionInterceptor(同名的),来覆盖此Bean(注意是覆盖)
	// 另外请注意:你自定义的BeanName必须同名,也就是必须名为:transactionInterceptor  否则两个都会注册进容器里面去~~~~~~
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionInterceptor transactionInterceptor() {
		TransactionInterceptor interceptor = new TransactionInterceptor();
		// 事务的属性
		interceptor.setTransactionAttributeSource(transactionAttributeSource());
		// 事务管理器(也就是注解最终需要使用的事务管理器,父类已经处理好了)
		// 此处注意:我们是可议不用特殊指定的,最终它自己会去容器匹配一个适合的~~~~
		if (this.txManager != null) {
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}

}

// 父类(抽象类)  它实现了ImportAware接口  所以拿到@Import所在类的所有注解信息
@Configuration
public abstract class AbstractTransactionManagementConfiguration implements ImportAware {

	@Nullable
	protected AnnotationAttributes enableTx;
	/**
	 * Default transaction manager, as configured through a {@link TransactionManagementConfigurer}.
	 */
	// 此处:注解的默认的事务处理器(可议通过实现接口TransactionManagementConfigurer来自定义配置)
	// 因为事务管理器这个东西,一般来说全局一个就行,但是Spring也提供了定制化的能力~~~
	@Nullable
	protected PlatformTransactionManager txManager;

	@Override
	public void setImportMetadata(AnnotationMetadata importMetadata) {
		// 此处:只拿到@EnableTransactionManagement这个注解的就成~~~~~ 作为AnnotationAttributes保存起来
		this.enableTx = AnnotationAttributes.fromMap(importMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName(), false));
		// 这个注解是必须的~~~~~~~~~~~~~~~~
		if (this.enableTx == null) {
			throw new IllegalArgumentException("@EnableTransactionManagement is not present on importing class " + importMetadata.getClassName());
		}
	}

	// 可以配置一个Bean实现这个接口。然后给注解驱动的给一个默认的事务管理器~~~~
	// 设计模式都是想通的~~~
	@Autowired(required = false)
	void setConfigurers(Collection<TransactionManagementConfigurer> configurers) {
		if (CollectionUtils.isEmpty(configurers)) {
			return;
		}
		// 同样的,最多也只允许你去配置一个~~~
		if (configurers.size() > 1) {
			throw new IllegalStateException("Only one TransactionManagementConfigurer may exist");
		}
		TransactionManagementConfigurer configurer = configurers.iterator().next();
		this.txManager = configurer.annotationDrivenTransactionManager();
	}

	// 注册一个监听器工厂,用以支持@TransactionalEventListener注解标注的方法,来监听事务相关的事件
	// 通过事件监听模式来实现事务的监控~~~~
	@Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public static TransactionalEventListenerFactory transactionalEventListenerFactory() {
		return new TransactionalEventListenerFactory();
	}

}

下面重中之重来了,那就是BeanFactoryTransactionAttributeSourceAdvisor这个增强器

BeanFactoryTransactionAttributeSourceAdvisor

首先看它的父类:AbstractBeanFactoryPointcutAdvisor它是一个和Bean工厂和事务都有关系的Advisor

从上面的配置类可议看出,它是new出来一个。

使用的Advice为:advisor.setAdvice(transactionInterceptor()),既容器内的事务拦截器~~~~

使用的事务属性源为:advisor.setTransactionAttributeSource(transactionAttributeSource()),既一个new AnnotationTransactionAttributeSource()支持三种事务注解来标注~~~

// @since 2.5.5
// 它是一个AbstractBeanFactoryPointcutAdvisor ,关于这个Advisor 请参阅之前的博文讲解~~~
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {

	@Nullable
	private TransactionAttributeSource transactionAttributeSource;

	// 这个很重要,就是切面。它决定了哪些类会被切入,从而生成的代理对象~
	// 关于:TransactionAttributeSourcePointcut 下面有说~
	private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
		// 注意此处`getTransactionAttributeSource`就是它的一个抽象方法~~~
		@Override
		@Nullable
		protected TransactionAttributeSource getTransactionAttributeSource() {
			return transactionAttributeSource;
		}
	};

	// 可议手动设置一个事务属性源~
	public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
		this.transactionAttributeSource = transactionAttributeSource;
	}

	// 当然我们可以指定ClassFilter  默认情况下:ClassFilter classFilter = ClassFilter.TRUE;  匹配所有的类的
	public void setClassFilter(ClassFilter classFilter) {
		this.pointcut.setClassFilter(classFilter);
	}

	// 此处pointcut就是使用自己的这个pointcut去切入~~~
	@Override
	public Pointcut getPointcut() {
		return this.pointcut;
	}

}

下面当然要重点看看TransactionAttributeSourcePointcut,它是怎么切入的

TransactionAttributeSourcePointcut

这个就是事务的匹配Pointcut切面,决定了哪些类需要生成代理对象从而应用事务。

// 首先它的访问权限事default 显示是给内部使用的
// 首先它继承自StaticMethodMatcherPointcut   所以`ClassFilter classFilter = ClassFilter.TRUE;` 匹配所有的类
// 并且isRuntime=false  表示只需要对方法进行静态匹配即可~~~~
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {

	// 方法的匹配  静态匹配即可(因为事务无需要动态匹配这么细粒度~~~)
	@Override
	public boolean matches(Method method, Class<?> targetClass) {
		// 实现了如下三个接口的子类,就不需要被代理了  直接放行
		// TransactionalProxy它是SpringProxy的子类。  如果是被TransactionProxyFactoryBean生产出来的Bean,就会自动实现此接口,那么就不会被这里再次代理了
		// PlatformTransactionManager:spring抽象的事务管理器~~~
		// PersistenceExceptionTranslator对RuntimeException转换成DataAccessException的转换接口
		if (TransactionalProxy.class.isAssignableFrom(targetClass) ||
				PlatformTransactionManager.class.isAssignableFrom(targetClass) ||
				PersistenceExceptionTranslator.class.isAssignableFrom(targetClass)) {
			return false;
		}

		// 重要:拿到事务属性源~~~~~~
		// 如果tas == null表示没有配置事务属性源,那是全部匹配的  也就是说所有的方法都匹配~~~~(这个处理还是比较让我诧异的~~~)
		// 或者 标注了@Transaction这样的注解的方法才会给与匹配~~~
		TransactionAttributeSource tas = getTransactionAttributeSource();
		return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
	}
	...
	// 由子类提供给我,告诉事务属性源~~~~ 我才好知道哪些方法我需要切嘛~~~
	@Nullable
	protected abstract TransactionAttributeSource getTransactionAttributeSource();
}

关于matches方法的调用时机:只要是容器内的每个Bean,都会经过AbstractAutoProxyCreator#postProcessAfterInitialization从而会调用wrapIfNecessary方法,因此容器内所有的Bean的所有方法在容器启动时候都会执行此matche方法,因此请注意缓存的使用~~~~~

解析advisor

https://www.processon.com/view/link/5f4f4c195653bb0c71e5f9f4

在Spring AOP中有过过介绍,解析事务advisor详细代码:org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans

public List<Advisor> findAdvisorBeans() {

   /**
    * 探测器字段缓存中cachedAdvisorBeanNames 是用来保存我们的Advisor全类名
    * 会在第一个单实例bean的中会去把这个advisor名称解析出来
    */
   String[] advisorNames = this.cachedAdvisorBeanNames;
   if (advisorNames == null) {
      /**
       * 去我们的容器中获取到实现了Advisor接口的实现类
       * 而我们的事务注解@EnableTransactionManagement 导入了一个叫ProxyTransactionManagementConfiguration配置类
       * 而在这个配置类中配置了
       * @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
         @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
         public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor();
         然后把他的名字获取出来保存到 本类的属性变量cachedAdvisorBeanNames中
       */
      advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
            this.beanFactory, Advisor.class, true, false);
      this.cachedAdvisorBeanNames = advisorNames;
   }
   //若在容器中没有找到,直接返回一个空的集合
   if (advisorNames.length == 0) {
      return new ArrayList<>();
   }

   List<Advisor> advisors = new ArrayList<>();
   //ioc容器中找到了我们配置的BeanFactoryTransactionAttributeSourceAdvisor
   for (String name : advisorNames) {
      //判断他是不是一个合适的 是我们想要的 默认true
      if (isEligibleBean(name)) {
         //BeanFactoryTransactionAttributeSourceAdvisor是不是正在创建的bean
         if (this.beanFactory.isCurrentlyInCreation(name)) {
            if (logger.isDebugEnabled()) {
               logger.debug("Skipping currently created advisor '" + name + "'");
            }
         }
         //不是的话
         else {
            try {
               //显示的调用getBean方法方法创建我们的BeanFactoryTransactionAttributeSourceAdvisor返回去
               advisors.add(this.beanFactory.getBean(name, Advisor.class));
            }
            catch (BeanCreationException ex) {
               Throwable rootCause = ex.getMostSpecificCause();
               if (rootCause instanceof BeanCurrentlyInCreationException) {
                  BeanCreationException bce = (BeanCreationException) rootCause;
                  String bceBeanName = bce.getBeanName();
                  if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
                     if (logger.isDebugEnabled()) {
                        logger.debug("Skipping advisor '" + name +
                              "' with dependency on currently created bean: " + ex.getMessage());
                     }
                     // Ignore: indicates a reference back to the bean we're trying to advise.
                     // We want to find advisors other than the currently created bean itself.
                     continue;
                  }
               }
               throw ex;
            }
         }
      }
   }
   return advisors;
}

去我们的容器中获取到实现了Advisor接口的实现类

显示的调用getBean方法方法创建我们的BeanFactoryTransactionAttributeSourceAdvisor返回去

创建动态代理

https://www.processon.com/view/link/5f507c7407912902cf700145

在Spring AOP中有过过介绍,区别在于匹配方式的不同:

  • AOP是按照Aspectj提供的API 结合切点表达式进行匹配。

  • 事务是根据方法或者类或者接口上面的@Transactional进行匹配。

所以本文和aop重复的就省略了如下:

// 创建Bean
createBean:524, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
// 执行带 Bean的生命周期的doCreateBean
doCreateBean:614, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
// 初始化方法
initializeBean:1931, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
// 执行初始化后的  BeanPostProcessor
applyBeanPostProcessorsAfterInitialization:445, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
// 调用创建动态代理方法   AbstractAutoProxyCreator.postProcessAfterInitialization
postProcessAfterInitialization:327, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy)
wrapIfNecessary:378, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy)
// 根据当前bean找到匹配的advisor
getAdvicesAndAdvisorsForBean:84, AbstractAdvisorAutoProxyCreator (org.springframework.aop.framework.autoproxy)
// 拿到before解析的所有adivsor做匹配
findEligibleAdvisors:106, AbstractAdvisorAutoProxyCreator (org.springframework.aop.framework.autoproxy)
findAdvisorsThatCanApply:144, AbstractAdvisorAutoProxyCreator (org.springframework.aop.framework.autoproxy)
findAdvisorsThatCanApply:344, AopUtils (org.springframework.aop.support)
// 根据TransactionAttributeSourcePointcut判断是否匹配
canApply:305, AopUtils (org.springframework.aop.support)

从该方法开始跟AOP有所区别了:

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
   Assert.notNull(pc, "Pointcut must not be null");
   // 进行类级别过滤 这里会返回
   if (!pc.getClassFilter().matches(targetClass)) {
      return false;
   }
   /**
    * 进行方法级别过滤
    */
   //如果pc.getMethodMatcher()返回TrueMethodMatcher则匹配所有方法
   MethodMatcher methodMatcher = pc.getMethodMatcher();
   if (methodMatcher == MethodMatcher.TRUE) {
      // No need to iterate the methods if we're matching any method anyway...
      return true;
   }

   //判断匹配器是不是IntroductionAwareMethodMatcher  只有AspectJExpressionPointCut才会实现这个接口
   IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
   if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
      introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
   }

   //创建一个集合用于保存targetClass 的class对象
   Set<Class<?>> classes = new LinkedHashSet<>();
   //判断当前class是不是代理的class对象
   if (!Proxy.isProxyClass(targetClass)) {
      //加入到集合中去
      classes.add(ClassUtils.getUserClass(targetClass));
   }
   //获取到targetClass所实现的接口的class对象,然后加入到集合中
   classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

   //循环所有的class对象
   for (Class<?> clazz : classes) {
      //通过class获取到所有的方法
      Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
      //循环我们的方法
      for (Method method : methods) {
         //通过methodMatcher.matches来匹配我们的方法
         if (introductionAwareMethodMatcher != null ?
               // 通过切点表达式进行匹配 AspectJ方式
               introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
               // 通过方法匹配器进行匹配 内置aop接口方式
               methodMatcher.matches(method, targetClass)) {
            // 只要有1个方法匹配上了就创建代理
            return true;
         }
      }
   }

   return false;
}

关键点:

  • if (!pc.getClassFilter().matches(targetClass)) {

  • 初筛时事务不像aop, 上面介绍的TransactionAttributeSourcePointcut的getClassFilter是TrueClassFilter。所以所有的类都能匹配

  • if (methodMatcher instanceof IntroductionAwareMethodMatcher) {

  • 事务的methodMatcher 没有实现该接口。 只有AOP的实现了该接口所以也导致下面:

  • methodMatcher.matches(method, targetClass)

  • 所以事务时直接调用methodMatcher.matches进行匹配

匹配方式:

1.org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut#matches

@Override
public boolean matches(Method method, @Nullable Class<?> targetClass) {
   if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {
      return false;
   }
   /**
    * 获取我们@EnableTransactionManagement注解为我们容器中导入的ProxyTransactionManagementConfiguration
        * 配置类中的TransactionAttributeSource对象
    */
   TransactionAttributeSource tas = getTransactionAttributeSource();
   // 通过getTransactionAttribute看是否有@Transactional注解
   return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}

关键点

  • TransactionAttributeSource tas = getTransactionAttributeSource();

  • 这里获取到的时候 通过@Import 的ImportSelect 注册的配置类ProxyTransactionManagementConfiguration 中设置的AnnotationTransactionAttributeSource:它是基于注解驱动的事务管理的事务属性源,和@Transaction相关,也是现在使用得最最多的方式。

它的基本作用为:它遇上比如@Transaction标注的方法时,此类会分析此事务注解,最终组织形成一个TransactionAttribute供随后的调用。

当然还有其他的类型 ,稍微举几个例:

  • NameMatchTransactionAttributeSource:根据名字就能匹配,然后该事务属性就会作用在对应的方法上。比如下面例子:
@Bean
public TransactionAttributeSource transactionAttributeSource() {
    Map<String, TransactionAttribute> txMap = new HashMap<>();
    // required事务  适用于增删改场景~
    RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute();
    requiredTx.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(RuntimeException.class)));
    requiredTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
    txMap.put("add*", requiredTx);
    txMap.put("save*", requiredTx);
    txMap.put("insert*", requiredTx);
    txMap.put("update*", requiredTx);
    txMap.put("delete*", requiredTx);

    // 查询 使用只读事务
    RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
    readOnlyTx.setReadOnly(true);
    readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
    txMap.put("get*", readOnlyTx);
    txMap.put("query*", readOnlyTx);

    NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
    source.setNameMap(txMap);

    return source;
}
  • MethodMapTransactionAttributeSource:它的使用方式和NameMatchTransactionAttributeSource基本相同,指定具体方法名

  • CompositeTransactionAttributeSource :组合模式,这里不细讲

2.org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute

public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
   //判断method所在的class 是不是Object类型
   if (method.getDeclaringClass() == Object.class) {
      return null;
   }

   //构建我们的缓存key
   Object cacheKey = getCacheKey(method, targetClass);
   //先去我们的缓存中获取
   TransactionAttribute cached = this.attributeCache.get(cacheKey);
   //缓存中不为空
   if (cached != null) {
      //判断缓存中的对象是不是空事务属性的对象
      if (cached == NULL_TRANSACTION_ATTRIBUTE) {
         return null;
      }
      //不是的话 就进行返回
      else {
         return cached;
      }
   }
   else {
      //我们需要查找我们的事务注解 匹配在这体现
      TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
      // 若解析出来的事务注解属性为空
      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;
   }
}

关键点:

  • if (cached != null) {

  • 先从缓存中取, 因为这个过程相对比较耗资源,会使用缓存存储已经解析过的, 后续调用时需要获取

  • TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);

  • 该方法中具体执行匹配过程 大致是: 实现类方法—>接口的方法—>实现类---->接口类

  • ((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);

  • 记录当前需要执行事务的方法名,记录到Descriptor 方便后续调用时判断

  • this.attributeCache.put(cacheKey, txAttr);

  • 加入到缓存中

  1. 看下是怎么匹配的:

org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#computeTransactionAttribute

@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
   //判断我们的事务方法上的修饰符是不是public的
   if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
      return null;
   }

   // 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 = AopUtils.getMostSpecificMethod(method, targetClass);

   //第一步,我们先去目标class的方法上去找我们的事务注解
   TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
   if (txAttr != null) {
      return txAttr;
   }

   //第二步:去我们targetClass类[实现类]上找事务注解
   txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
   if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
      return txAttr;
   }
   // 具体方法不是当前的方法说明  当前方法是接口方法
   if (specificMethod != method) {
      //去我们的实现类的接口上的方法去找事务注解
      txAttr = findTransactionAttribute(method);
      if (txAttr != null) {
         return txAttr;
      }
      //去我们的实现类的接口上去找事务注解
      txAttr = findTransactionAttribute(method.getDeclaringClass());
      if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
         return txAttr;
      }
   }

   return null;
}

关键点:

这个方法乍一看,觉得是先从实现类方法–>实现类—>接口方法—>接口类 但是!!!! 他在第一个实现方法查找就已经找了接口方法父类方法。在实现类里面就找了接口类和父类, 所以接口方法—>接口类 基本走了也没啥用

  • Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);

  • 得到具体方法, 如果method是接口方法那将从targetClass得到实现类的方法 , 所以说无论传的是接口还是实现, 都会先解析实现类, 所以接口传进来基本没啥用,因为findTransactionAttribute方法本身就会去接口中解析

  • TransactionAttribute txAttr = findTransactionAttribute(specificMethod);

  • 根据具体方法解析

  • txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());

  • 根据实现类解析

@Transactional简单解释

这个事务注解可以用在类上,也可以用在方法上。

  • 将事务注解标记到服务组件类级别,相当于为该服务组件的每个服务方法都应用了这个注解

  • 事务注解应用在方法级别,是更细粒度的一种事务注解方式

注意 : 如果某个方法和该方法所属类上都有事务注解属性,优先使用方法上的事务注解属性。

另外,Spring 支持三个不同的事务注解 :

  1. Spring 事务注解 org.springframework.transaction.annotation.Transactional(纯正血统,官方推荐)

  2. JTA事务注解 javax.transaction.Transactional

  3. EJB 3 事务注解 javax.ejb.TransactionAttribute

上面三个注解虽然语义上一样,但是使用方式上不完全一样,若真要使其它的时请注意各自的使用方式~

所以, 我们来看下Spring 事务注解:SpringTransactionAnnotationParser的解析:

findTransactionAttribute:146, AnnotationTransactionAttributeSource (org.springframework.transaction.annotation)

determineTransactionAttribute:164, AnnotationTransactionAttributeSource (org.springframework.transaction.annotation)

parseTransactionAnnotation:46, SpringTransactionAnnotationParser (org.springframework.transaction.annotation)

findMergedAnnotationAttributes:607, AnnotatedElementUtils (org.springframework.core.annotation)

searchWithFindSemantics:981, AnnotatedElementUtils (org.springframework.core.annotation)

searchWithFindSemantics:1009, AnnotatedElementUtils (org.springframework.core.annotation)

org.springframework.core.annotation.AnnotatedElementUtils#searchWithFindSemantics:

这是个公共方法, 根据传入的注解类型和元素进行匹配

  • 最终会解析成TransactionAttribute

OK,解析完成!!!

  • 记录当前需要执行事务的方法名,记录到descriptor 方便后续调用时判断

  • 加入到缓存

this.attributeCache.put(cacheKey, txAttr);

  • 如果txAttr!=null 说明解析成功,return true 匹配成功!

  • 创建动态代理跟Aop的逻辑是一样的,这里就不详细说了

调用代理对象

https://www.processon.com/view/link/5f50d4c75653bb53ea8df95a

调用开始和AOP是一样的,这里省略之前的代码:

最终调用org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

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

   //获取我们的事务属源对象 在配置类中添加的, 在创建代理进行匹配的时候还用了它还记得吗(将解析的事务属性赋值进去了)
   TransactionAttributeSource tas = getTransactionAttributeSource();
   // 获取解析后的事务属性信息,
   //  创建代理的时候也调用了getTransactionAttribute还记得吗, 如果解析到了事务属性就可以创建代理,
   //  在这里是从解析后的缓存中获取
   final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
   // 获取我们配置的事务管理器对象 在我们自己的配置类里面配置的
   final PlatformTransactionManager tm = determineTransactionManager(txAttr);
   // 从tx属性对象中获取出标注了@Transactionl的方法描述符
   // 之前往descriptor中设置的还记得吧
   final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

   //处理声明式事务
   if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
      //有没有必要创建事务
      TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);

      Object retVal;
      try {
         //调用钩子函数进行回调目标方法
         retVal = invocation.proceedWithInvocation();
      }
      catch (Throwable ex) {
         //抛出异常进行回滚处理
         completeTransactionAfterThrowing(txInfo, ex);
         throw ex;
      }
      finally {
         //清空我们的线程变量中transactionInfo的值
         cleanupTransactionInfo(txInfo);
      }
      //提交事务
      commitTransactionAfterReturning(txInfo);
      return retVal;
   }
   // 编程式事务:(回调偏向)
   else {
       ...
   }
}

方法概览:

关键点:

  • 前面4行都是获取一些基本信息

  • createTransactionIfNecessary 这个方法逻辑最多,事务传播行为等实现都是在这种方法

  • 如果有必要会创建一个事务,什么是有必要?

  • try 中回调"连接点(事务的方法)"

  • catch中出现异常回滚事务

  • commitTransactionAfterReturning 提交事务

着重看一下createTransactionIfNecessary的逻辑实现

protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
      @Nullable TransactionAttribute txAttr, final String joinpointIdentification) {

   // 如果还没有定义名字,把连接点的ID定义成事务的名称
   if (txAttr != null && txAttr.getName() == null) {
      txAttr = new DelegatingTransactionAttribute(txAttr) {
         @Override
         public String getName() {
            return joinpointIdentification;
         }
      };
   }

   TransactionStatus status = null;
   if (txAttr != null) {
      if (tm != null) {
         //获取一个事务状态
         status = tm.getTransaction(txAttr);
      }
      else {
         if (logger.isDebugEnabled()) {
            logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
                  "] because no transaction manager has been configured");
         }
      }
   }
   //把事物状态和事物属性等信息封装成一个TransactionInfo对象
   return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}

关键点:

  • 将之前的Descriptor 作为事务名称

  • 这里重点看下tm.getTransaction

  • tm 是我们在配置类 中的transactionManager

@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
}

所以重点看下tm.getTransaction

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
   //尝试获取一个事务对象
   Object transaction = doGetTransaction();

   // Cache debug flag to avoid repeated checks.
   boolean debugEnabled = logger.isDebugEnabled();

   /**
    * 判断从上一个方法传递进来的事务属性是不是为空
    */
   if (definition == null) {

      definition = new DefaultTransactionDefinition();
   }

   /**
    * 判断是不是已经存在了事务对象(事务嵌套)
    */
   if (isExistingTransaction(transaction)) {
      //处理存在的事务
      return handleExistingTransaction(definition, transaction, debugEnabled);
   }

   //检查事务设置的超时时间
   if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
      throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
   }

   /**
    * 若当前的事务属性式 PROPAGATION_MANDATORY 表示必须运行在事务中,若当前没有事务就抛出异常
    * 由于isExistingTransaction(transaction)跳过了这里,说明当前是不存在事务的,那么就会抛出异常
    */
   if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
      throw new IllegalTransactionStateException(
            "No existing transaction found for transaction marked with propagation 'mandatory'");
   }
   /**
    * PROPAGATION_REQUIRED 当前存在事务就加入到当前的事务,没有就新开一个
    * PROPAGATION_REQUIRES_NEW:新开一个事务,若当前存在事务就挂起当前事务
    * PROPAGATION_NESTED: PROPAGATION_NESTED
       表示如果当前正有一个事务在运行中,则该方法应该运行在 一个嵌套的事务中,
       被嵌套的事务可以独立于封装事务进行提交或者回滚(保存点),
       如果封装事务不存在,行为就像 PROPAGATION_REQUIRES NEW
    */
   else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
         definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
         definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
      /**
       * 挂起当前事务,在这里为啥传入null?
       * 因为逻辑走到这里了,经过了上面的isExistingTransaction(transaction) 判断当前是不存在事务的
       * 所有再这里是挂起当前事务传递一个null进去
       */
      SuspendedResourcesHolder suspendedResources = suspend(null);
      if (debugEnabled) {
         logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
      }
      try {
         //  意思是可以进行同步
         boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
         // 构造事务状态对象,newTransaction=true代表是一个新事务
         DefaultTransactionStatus status = newTransactionStatus(
               definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
         //开启一个新的事物
         doBegin(transaction, definition);
         //把当前的事务信息绑定到线程变量去
         prepareSynchronization(status, definition);
         return status;
      }
      catch (RuntimeException | Error ex) {
         resume(null, suspendedResources);
         throw ex;
      }
   }
   else { //创建一个空的事务
      // Create "empty" transaction: no actual transaction, but potentially synchronization.
      if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
         logger.warn("Custom isolation level specified but no actual transaction initiated; " +
               "isolation level will effectively be ignored: " + definition);
      }
      boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
      return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
   }
}

关键点:可以看到这个方法里面做了很多关于事务的逻辑实现

  • Object transaction = doGetTransaction();

  • 获得事务对象,这里事务是否存在主要看它携带的ConnectionHolder(数据库连接持有者),如果ConnectionHolder有则基本说明存在事务,什么情况下会存在已存在事务? ——嵌套事务

  • if (isExistingTransaction(transaction)) {

  • 这里判断是否存在事务,

  • 如果已存在就处理嵌套的事务逻辑, 这里我们待会作为分支再来跟进

  • 如果不存在就处理顶层的事务逻辑,下面将先介绍顶层的事务逻辑

顶层的事务逻辑

  • 处理不同的传播行为,看这之前我们先了解一下事务的传播行为
事务传播行为类型 外部不存在事务 外部存在事务 使用方式
REQUIRED(默认) 开启新的事务 融合到外部事务中 @Transactional(propagation = Propagation.REQUIRED)
适用增删改查
SUPPORTS 不开启新的事务 融合到外部事务中 @Transactional(propagation = Propagation.SUPPORTS)
适用查询
REQUIRES_NEW 开启新的事务 挂起外部事务,创建新的事务 @Transactional(propagation = Propagation.REQUIRES_NEW)
适用内部事务和外部事务不存在业务关联情况,如日志
NOT_SUPPORTED 不开启新的事务 挂起外部事务,不开启事务 @Transactional(propagation = Propagation.NOT_SUPPORTED)
不常用
NEVER 不开启新的事务 抛出异常 @Transactional(propagation = Propagation.NEVER )
不常用
MANDATORY 抛出异常 融合到外部事务中 @Transactional(propagation = Propagation.MANDATORY)
不常用
NESTED 开启新的事务 融合到外部事务中,SavePoint机制,外层影响内层, 内层不会影响外层 @Transactional(propagation = Propagation.NESTED)
不常用
  • PROPAGATION_MANDATORY

  • 当事务传播行为是MANDATORY , 所以这里直接抛出异常

  • PROPAGATION_REQUIRED || PROPAGATION_REQUIRES_NEW || PROPAGATION_NESTED

  • 当事务传播行为是REQUIRED 或者 REQUIRES_NEW 或者 NESTED 都将开启一个新的事务,怎么开启:

  1. suspend(null); 挂起当前事务, 顶层事务当前还没创建事务,没啥可挂的,所以传个null进去

  2. newSynchronization 允许开启同步事务

  3. newTransactionStatus 构造事务状态对象, 并且把事务的信息封装进去:

  4. definition, 事务的属性

  5. transaction, 事务的对象

  6. true, 代表是一个新的事务

  7. doBegin(transaction, definition); 开启一个新事务, 这里跟进去看下怎么开启的

  8. prepareSynchronization(status, definition);

  9. 把当前的事务信息绑定到线程变量去: 为什么要绑定要线程变量呢? 因为存在嵌套事务情况下需要用到

// 事务的名称
private static final ThreadLocal<String> currentTransactionName = new NamedThreadLocal<>("Current transaction name");
// 是否为只读事务
private static final ThreadLocal<Boolean> currentTransactionReadOnly = new NamedThreadLocal<>("Current transaction read-only status");
// 当前事务的隔离级别
private static final ThreadLocal<Integer> currentTransactionIsolationLevel = new NamedThreadLocal<>("Current transaction isolation level");
// 当前事务是否激活  ,怎么样算激活:  就是有事务就是已开启, 当然到这一步一般就有事务的,因为执行doBegin就开启了
private static final ThreadLocal<Boolean> actualTransactionActive = new NamedThreadLocal<>("Actual transaction active");

看下doBegin

protected void doBegin(Object transaction, TransactionDefinition definition) {
   //强制转化事物对象
   DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
   Connection con = null;

   try {
      //判断事务对象没有数据库连接持有器
      if (!txObject.hasConnectionHolder() ||
            txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
         //通过数据源获取一个数据库连接对象
         Connection newCon = obtainDataSource().getConnection();
         if (logger.isDebugEnabled()) {
            logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
         }
         //把我们的数据库连接包装成一个ConnectionHolder对象 然后设置到我们的txObject对象中去
         txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
      }

      //标记当前的连接是一个同步事务...?
      txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
      con = txObject.getConnectionHolder().getConnection();

      // 设置isReadOnly、隔离级别
      Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
      txObject.setPreviousIsolationLevel(previousIsolationLevel);

      //setAutoCommit 默认为true,即每条SQL语句在各自的一个事务中执行。
      if (con.getAutoCommit()) {
         txObject.setMustRestoreAutoCommit(true);
         if (logger.isDebugEnabled()) {
            logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
         }
         con.setAutoCommit(false); // 开启事务
      }

      //判断事务为只读事务
      prepareTransactionalConnection(con, definition);
      //设置事务激活
      txObject.getConnectionHolder().setTransactionActive(true);

      //设置事务超时时间
      int timeout = determineTimeout(definition);
      if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
         txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
      }

      // 绑定我们的数据源和连接到我们的同步管理器上   把数据源作为key,数据库连接作为value 设置到线程变量中
      if (txObject.isNewConnectionHolder()) {
         TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
      }
   }

   ...
}

关键点:

  • txObject.setConnectionHolder(new ConnectionHolder(newCon), true);

  • 获取一个数据库Connection,封装到ConnectionHolder中, 是不是跟上面doGetTransaction();上下呼应了。 所以假如存在嵌套事务, 就可以拿到ConnectionHolder了

  • txObject.getConnectionHolder().setTransactionActive(true);

  • 开启事务后将事务激活, 又上下呼应了

到这里,如果不存在嵌套事务的话 事务的主要逻辑代码就是这些。

嵌套的事务逻辑

ps:注意 要触发嵌套事务 如果是调用本类的方法一定要保证 将动态代理暴露在线程中:

@EnableAspectJAutoProxy(exposeProxy = true)

通过当前线程代理调用才能触发本类方法的调用:((PayService)AopContext.currentProxy()).updateProductStore(1);

在pay方法基础上加入嵌套事务方法:

public void pay(String accountId, double money) {
    //更新余额
     int retVal = accountInfoDao.updateAccountBlance(accountId,money);

    ((PayService)AopContext.currentProxy()).updateProductStore(1);
    System.out.println(1/0);

}

我们就从嵌套方法第5行开始跟踪调试:

 ((PayService)AopContext.currentProxy()).updateProductStore(1);

同样也会来到:

org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary

org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction

@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
   //尝试获取一个事务对象
   Object transaction = doGetTransaction();

   // Cache debug flag to avoid repeated checks.
   boolean debugEnabled = logger.isDebugEnabled();

   /**
    * 判断从上一个方法传递进来的事务属性是不是为空
    */
   if (definition == null) {

      definition = new DefaultTransactionDefinition();
   }

   /**
    * 判断是不是已经存在了事务对象(事务嵌套)
    */
   if (isExistingTransaction(transaction)) {
      //处理存在的事务
      return handleExistingTransaction(definition, transaction, debugEnabled);
   }

    ...省略
}
  • doGetTransaction 将能获得ConnectionHolder,因为顶层事务在开启事务时已经存储。 已经存在事务意味着什么不用我说了吧

  • if (isExistingTransaction(transaction)) {

  • 成立!因为事务ConnectionHolder已经存在 并且 已经激活(在doBegin中激活的)。 执行嵌套事务handleExistingTransaction

handleExistingTransaction执行嵌套事务

private TransactionStatus handleExistingTransaction(
      TransactionDefinition definition, Object transaction, boolean debugEnabled)
      throws TransactionException {

   /**
    * NEVER  存在外部事务: 抛出异常
    */
   if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
      throw new IllegalTransactionStateException(
            "Existing transaction found for transaction marked with propagation 'never'");
   }

   /**
    * NOT_SUPPORTED 存在外部事务: 挂起外部事务
    */
   if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
      if (debugEnabled) {
         logger.debug("Suspending current transaction");
      }
      //挂起存在的事物
      Object suspendedResources = suspend(transaction);
      boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
      //创建一个新的非事物状态(保存了上一个存在事物状态的属性)
      return prepareTransactionStatus(
            definition, null, false, newSynchronization, debugEnabled, suspendedResources);
   }

   /**
    * REQUIRES_NEW 存在外部事务: 挂起外部事务,创建新的事务
    */
   if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
      if (debugEnabled) {
         logger.debug("Suspending current transaction, creating new transaction with name [" +
               definition.getName() + "]");
      }
      //挂起已经存在的事物
      SuspendedResourcesHolder suspendedResources = suspend(transaction);
      try {
         // 是否需要新开启同步
         boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
         //创建一个新的事物状态(包含了挂起的事务的属性)
         DefaultTransactionStatus status = newTransactionStatus(
               definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
         //开启新的事物
         doBegin(transaction, definition);
         //把新的事物状态设置到当前的线程变量中去
         prepareSynchronization(status, definition);
         return status;
      }
      catch (RuntimeException | Error beginEx) {
         resumeAfterBeginException(transaction, suspendedResources, beginEx);
         throw beginEx;
      }
   }

   /**
    *NESTED 存在外部事务: 融合到外部事务中  应用层面和REQUIRED一样, 源码层面
    */
   if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
      if (!isNestedTransactionAllowed()) {
         throw new NestedTransactionNotSupportedException(
               "Transaction manager does not allow nested transactions by default - " +
               "specify 'nestedTransactionAllowed' property with value 'true'");
      }
      if (debugEnabled) {
         logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
      }
      // 是否支持保存点:非JTA事务走这个分支。AbstractPlatformTransactionManager默认是true,JtaTransactionManager复写了该方法false,DataSourceTransactionManager没有复写,还是true,
      if (useSavepointForNestedTransaction()) {
         //开启一个新的事物
         DefaultTransactionStatus status =
               prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
         // 为事物设置一个回退点
         // savepoint 可以在一组事务中,设置一个回滚点,点以上的不受影响,点以下的回滚。(外层影响内层, 内层不会影响外层)
         status.createAndHoldSavepoint();
         return status;
      }
      else { //  JTA事务走这个分支,创建新事务
         boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
         DefaultTransactionStatus status = newTransactionStatus(
               definition, transaction, true, newSynchronization, debugEnabled, null);
         doBegin(transaction, definition);
         prepareSynchronization(status, definition);
         return status;
      }
   }

   // Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
   if (debugEnabled) {
      logger.debug("Participating in existing transaction");
   }
   if (isValidateExistingTransaction()) {
      if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
         Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
         if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
            Constants isoConstants = DefaultTransactionDefinition.constants;
            throw new IllegalTransactionStateException("Participating transaction with definition [" +
                  definition + "] specifies isolation level which is incompatible with existing transaction: " +
                  (currentIsolationLevel != null ?
                        isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
                        "(unknown)"));
         }
      }
      if (!definition.isReadOnly()) {
         if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
            throw new IllegalTransactionStateException("Participating transaction with definition [" +
                  definition + "] is not marked as read-only but existing transaction is");
         }
      }
   }
   boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
   return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}

关键点:

  • 根据事务传播行为作处理:
事务传播行为类型 外部不存在事务 外部存在事务 使用方式
REQUIRED(默认) 开启新的事务 融合到外部事务中 @Transactional(propagation = Propagation.REQUIRED)
适用增删改查
SUPPORTS 不开启新的事务 融合到外部事务中 @Transactional(propagation = Propagation.SUPPORTS)
适用查询
REQUIRES_NEW 开启新的事务 挂起外部事务,创建新的事务 @Transactional(propagation = Propagation.REQUIRES_NEW)
适用内部事务和外部事务不存在业务关联情况,如日志
NOT_SUPPORTED 不开启新的事务 挂起外部事务 @Transactional(propagation = Propagation.NOT_SUPPORTED)
不常用
NEVER 不开启新的事务 抛出异常 @Transactional(propagation = Propagation.NEVER )
不常用
MANDATORY 抛出异常 融合到外部事务中 @Transactional(propagation = Propagation.MANDATORY)
不常用
NESTED 开启新的事务 融合到外部事务中,SavePoint机制,外层影响内层, 内层不会影响外层 @Transactional(propagation = Propagation.NESTED)
不常用
  • PROPAGATION_NEVER 抛出异常

  • 当事务传播行为是MANDATORY ,外部存在事务抛出异常: 所以这里直接抛出异常

  • PROPAGATION_NOT_SUPPORTED 挂起外部事务,不开启事务提交

  1. suspend(transaction); 挂起当前顶层事务,怎么挂呢? 其实就是将线程变量里面的事务信息拿出来,再置空。 待事务提交或回滚后再放回线程变量中

  1. newSynchronization 允许开启同步事务

  2. newTransactionStatus 构造事务状态对象, 并且把事务的信息封装进去:

  3. definition, 事务的属性

  4. transaction, null 因为它不开启事务

  5. false, 不是新事务

  6. suspendedResources 挂起的事务对象,在事务提交或回滚后会调用重新放回线程变量中

  7. prepareSynchronization(status, definition);

把当前的事务信息绑定到线程变量去: 为什么要绑定要线程变量呢? 因为存在嵌套事务情况下需要用到

  • PROPAGATION_REQUIRES_NEW 挂起外部事务,创建新的事务
  1. suspend(null); 挂起当前顶层事务,怎么挂呢? 其实就是将线程变量里面的事务信息拿出来,再置空。 待事务提交或回滚后再放回线程变量中

  2. newSynchronization 允许开启同步事务

  3. newTransactionStatus 构造事务状态对象, 并且把事务的信息封装进去:

  4. definition, 事务的属性

  5. transaction, 事务的对象

  6. true, 代表是一个新的事务

  7. suspendedResources 挂起的事务对象,在事务提交或回滚后会调用重新放回线程变量中

  8. doBegin(transaction, definition); 开启一个新事务, 这里跟进去看下怎么开启的

  9. prepareSynchronization(status, definition);

  10. 把当前的事务信息绑定到线程变量去: 为什么要绑定要线程变量呢? 因为存在嵌套事务情况下需要用到

  • PROPAGATION_NESTED 融合到外部事务中,SavePoint机制,外层影响内层, 内层不会影响外层

  • 这个不做过多介绍, 去了解一下jdbc的Savepoint自然就懂了

  • return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);

  1. definition, 原事务的属性

  2. transaction, 原事务的对象

  3. newTransaction:false, 代表不是一个新的事务,如果不是新事务,提交事务时: 由外层事务控制统一提交事务

所以最终返回一个DefaultTransactionStatus, 后续回滚、提交 都可以根据改对象进行控制。 回滚提交逻辑比较简单不在这里重复了

问题

简述Spring事务的原理机制。

描述事务的各传播机制及原理

文档:04-声明式事务源码.note

链接:http://note.youdao.com/noteshare?id=662f507915ff5e09b69d293965cb6f16&sub=08EAA9ACDE174C35BFA2541BA0056AAD

0

评论区