第五章 Spring事務源碼分析筆記

一、Spring事務實現

1、事務註解實現方式及配置

Spring中事務也是用AOP切面技術來實現的。

1.1、首先用註解的方式引入事務管理功能:

代碼如下:

@Component
@EnableTransactionManagement(proxyTargetClass = false)
@MapperScan(basePackages = {"com.chj.dao"},annotationClass = Repository.class)
public class EnableTransactionManagementBean {
    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean;
    }
    //這樣也可以
    @Bean
    public PlatformTransactionManager annotationDrivenTransactionManager(DataSource dataSource) {
        DataSourceTransactionManager dtm = new DataSourceTransactionManager();
        dtm.setDataSource(dataSource);
        return dtm;
    }
    @Bean
    public TransactionTemplate transactionTemplate(PlatformTransactionManager platformTransactionManager) {
        TransactionTemplate transactionTemplate = new TransactionTemplate();
        transactionTemplate.setTransactionManager(platformTransactionManager);
        return transactionTemplate;
    }
}

引用這個註解就顯示的添加了註解事務功能,但是我們自己還是需要定義數據源和事務管理平臺的:

1.2、數據源定義:

com.chj.datasource.DataSourceConfiguration

@Configuration
@PropertySource("classpath:config/core/core.properties")
public class DataSourceConfiguration {
    @Value("${jdbc.driverClassName}")
    private String driverClass;
    @Value("${jdbc.url:jdbc}")
    private String jdbcUrl;
    @Value("${jdbc.username}")
    private String user;
    @Value("${jdbc.password}")
    private String password;
    @Resource
    Environment environment;
//    @Bean
    public DataSource comboPooledDataSource() {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        try {
            comboPooledDataSource.setDriverClass(driverClass);
            comboPooledDataSource.setJdbcUrl(jdbcUrl);
            comboPooledDataSource.setUser(user);
            comboPooledDataSource.setPassword(password);
            comboPooledDataSource.setMinPoolSize(10);
            comboPooledDataSource.setMaxPoolSize(100);
            comboPooledDataSource.setMaxIdleTime(1800);
            comboPooledDataSource.setAcquireIncrement(3);
            comboPooledDataSource.setMaxStatements(1000);
            comboPooledDataSource.setInitialPoolSize(10);
            comboPooledDataSource.setIdleConnectionTestPeriod(60);
            comboPooledDataSource.setAcquireRetryAttempts(30);
            comboPooledDataSource.setBreakAfterAcquireFailure(false);
            comboPooledDataSource.setTestConnectionOnCheckout(false);
            comboPooledDataSource.setAcquireRetryDelay(100);
        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }
        return comboPooledDataSource;
    }
    @Bean
    public DataSource dynamicDataSource() {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        try {
            comboPooledDataSource.setDriverClass(driverClass);
            comboPooledDataSource.setJdbcUrl(jdbcUrl);
            comboPooledDataSource.setUser(user);
            comboPooledDataSource.setPassword(password);
            comboPooledDataSource.setMinPoolSize(10);
            comboPooledDataSource.setMaxPoolSize(100);
            comboPooledDataSource.setMaxIdleTime(1800);
            comboPooledDataSource.setAcquireIncrement(3);
            comboPooledDataSource.setMaxStatements(1000);
            comboPooledDataSource.setInitialPoolSize(10);
            comboPooledDataSource.setIdleConnectionTestPeriod(60);
            comboPooledDataSource.setAcquireRetryAttempts(30);
            comboPooledDataSource.setBreakAfterAcquireFailure(false);
            comboPooledDataSource.setTestConnectionOnCheckout(false);
            comboPooledDataSource.setAcquireRetryDelay(100);
        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("ds1",comboPooledDataSource);
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(comboPooledDataSource);
        return dynamicDataSource;
    }
}

1.3、定義事務管理平臺:

//@Component
public class TransactionManagementConfigurerBean implements TransactionManagementConfigurer {
    @Autowired
    private DataSource dataSource;
    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager() {
        DataSourceTransactionManager dtm = new DataSourceTransactionManager();
        dtm.setDataSource(dataSource);
        return dtm;
    }
}

數據源和事務管理平臺的加載都是在類ProxyTransactionManagementConfiguration進行的。

2、事務標籤解析以及入口分析

spring-tx-5.1.3.RELEASE.jar!\META-INF\spring.handlers

http\://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler

org.springframework.transaction.config.TxNamespaceHandler

public class TxNamespaceHandler extends NamespaceHandlerSupport {
   static final String TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager";
   static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";
   static String getTransactionManagerName(Element element) {
      return (element.hasAttribute(TRANSACTION_MANAGER_ATTRIBUTE) ?
            element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE) : DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);
   }
   @Override
   public void init() {
      registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
      registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
      registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
   }
}

org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser#parse

@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
   registerTransactionalEventListenerFactory(parserContext);
   String mode = element.getAttribute("mode");
   if ("aspectj".equals(mode)) {
      // mode="aspectj"
      registerTransactionAspect(element, parserContext);
      if (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader())) {
         registerJtaTransactionAspect(element, parserContext);
      }
   }
   else { // mode="proxy"
      AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
   }
   return null;
}

2.1、事務代理入口類分析:

org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser.AopAutoProxyConfigurer#configureAutoProxyCreator

private static class AopAutoProxyConfigurer {
   public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
      AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
      String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
      if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
         Object eleSource = parserContext.extractSource(element);
         // Create the TransactionAttributeSource definition.
         RootBeanDefinition sourceDef = new RootBeanDefinition(
               "org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
         sourceDef.setSource(eleSource);
         sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
         String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
         // Create the TransactionInterceptor definition.
         RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
         interceptorDef.setSource(eleSource);
         interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
         registerTransactionManager(element, interceptorDef);
         interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
         String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
         // Create the TransactionAttributeSourceAdvisor definition.
         RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
         advisorDef.setSource(eleSource);
         advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
         advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
         advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
         if (element.hasAttribute("order")) {
            advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
         }
         parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);
         CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
         compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
         compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
         compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
         parserContext.registerComponent(compositeDef);
      }
   }
}

2.2、事務代理對象創建

org.springframework.aop.config.AopNamespaceUtils#registerAutoProxyCreatorIfNecessary

public static void registerAutoProxyCreatorIfNecessary(
      ParserContext parserContext, Element sourceElement) {
   BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary(
         parserContext.getRegistry(), parserContext.extractSource(sourceElement));
   useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
   registerComponentIfNecessary(beanDefinition, parserContext);
}

把AOP入口類封裝成beanDefinition對象,把beanDefinition緩存到map中,然後實例化:

org.springframework.aop.config.AopConfigUtils#registerOrEscalateApcAsRequired

@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
      Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
   Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
   if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
      BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
      if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
         int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
         int requiredPriority = findPriorityForClass(cls);
         if (currentPriority < requiredPriority) {
            apcDefinition.setBeanClassName(cls.getName());
         }
      }
      return null;
   }
   //把AOP入口類封裝成beanDefinition對象,要實例化
   RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
   beanDefinition.setSource(source);
   beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
   beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
   //註解aop入口類的beanName名稱 AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME
   registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
   return beanDefinition;
}

代理類自動創建的核心

org.springframework.aop.config.AopConfigUtils

public abstract class AopConfigUtils {
   //The bean name of the internally managed auto-proxy creator.
   public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
         "org.springframework.aop.config.internalAutoProxyCreator";
   //Stores the auto proxy creator classes in escalation order.
   private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);
   static {
      // Set up the escalation list...優先級由低到高
      APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);

// xml配置方式解析
      APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);

// 註解配置方式解析
      APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
   }

org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition

else {
   //把beanDefinition緩存到map中
   // Still in startup registration phase
   this.beanDefinitionMap.put(beanName, beanDefinition);
   //把beanName放到beanDefinitionNames list中,這個list着重記住,bean實例化的時候需要用到
   this.beanDefinitionNames.add(beanName);
   this.manualSingletonNames.remove(beanName);
}

/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

2.3、事務操作入口(開啓、提交、回滾)

org.springframework.transaction.interceptor.TransactionInterceptor#invoke

@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
   Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
   // Adapt to TransactionAspectSupport's invokeWithinTransaction...
   return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}

org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
      final InvocationCallback invocation) throws Throwable {
   // If the transaction attribute is null, the method is non-transactional.
   //獲取事務屬性類 AnnotationTransactionAttributeSource
   TransactionAttributeSource tas = getTransactionAttributeSource();
   //獲取方法上面有@Transactional註解的屬性
   final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
   //獲取事務管理器
   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;
   }

備註:具體細節後面分析

3在理解spring事務的時候必須牢記的幾個概念:

Connection連接、事務、和用戶會話

我們在看了jdbc代碼以後可以清楚的知道,事務就是由connection對象控制的,所以connection對象是和事務是綁定的,然後用戶請求過來時又需要數據庫連接來執行sql語句,所以用戶請求線程又是跟connection是綁定的。

spring中事務傳播屬性有如下幾種:

PROPAGATION_REQUIRED如果當前沒有事務,就新建一個事務,如果已經存在一個事務中,加入到這個事務中。這是最常見的選擇。

PROPAGATION_SUPPORTS支持當前事務,如果當前沒有事務,就以非事務方式執行。

PROPAGATION_MANDATORY使用當前的事務,如果當前沒有事務,就拋出異常。

PROPAGATION_REQUIRES_NEW新建事務,如果當前存在事務,把當前事務掛起。

PROPAGATION_NOT_SUPPORTED以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。

PROPAGATION_NEVER以非事務方式執行,如果當前存在事務,則拋出異常。

PROPAGATION_NESTED如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則執行與PROPAGATION_REQUIRED類似的操作。

其中最常見的,用得最多就是:

PROPAGATION_REQUIREDPROPAGATION_REQUIRES_NEWPROPAGATION_NESTED這三種。

事務的傳播屬性是spring特有的,是spring用來控制方法事務的一種手段,說直白點就是用來控制方法是否使用同一事務的一種屬性,以及按照什麼規則回滾的一種手段。

 

二、傳播屬性的事務控制1

1、事務傳播屬性概念:

 

1.1、未提交讀read uncommited

假如開啓了兩個事務,事務1的隔離級別爲未提交讀,然後開啓事務進行查詢(不提交),事務2同一個表中插入一條數據,然後繼續執行事務1的查詢操作發現可以查詢到事務2中插入的數據。

1.2、讀已提交read commit

同樣開始兩個事務,事務1查詢數據,隔離級別爲read commit(未提交),事務2繼續執行插入操作,這個時候回到事務1中繼續查詢,發現兩次查詢的結果不一樣,這也就是所謂的的幻讀。

1.3、可重複讀repeatable read

同樣開始兩個事務,事務級別爲repeatable read,操作步驟同上,發現兩次查詢的結果是一致的;如果這個時候我們在事務1中插入一條數據不存在的數據(已刪除的數據),但是發現數據插入失敗,這也是幻讀現象。

 

1.4、可串行化

就是將事務一個接一個的串行化的去執行,這種方式可以解決幻讀但是效率非常低下。

行鎖:

如果多個事務操作同一行數據,比如修改同一條數據,那麼同事只是成功一條,其實就是等於給這條數據加鎖,先獲得鎖的事務先操作。

2、獲取事務屬性對象

2.1、入口代碼分析

這個類是事務切面的Advice,所有有關spring的事務控制邏輯都在這個類裏面。

com.chj.transaction.EnableTransactionManagementBean

@Component
@EnableTransactionManagement(proxyTargetClass = false)
@MapperScan(basePackages = {"com.chj.dao"},annotationClass = Repository.class)
public class EnableTransactionManagementBean {

org.springframework.transaction.annotation.EnableTransactionManagement

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

org.springframework.transaction.annotation.TransactionManagementConfigurationSelector

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
   /**
    * ConfigurationClassPostProcessor
    * ConfigurationClassParser  569行掉的
    * 收集beanName,然後封裝成beanDefinition對象
    */
   @Override
   protected String[] selectImports(AdviceMode adviceMode) {
      switch (adviceMode) {
         case PROXY:
            return new String[] {AutoProxyRegistrar.class.getName(),
                  ProxyTransactionManagementConfiguration.class.getName()};
         case ASPECTJ:
            return new String[] {determineTransactionAspectClass()};
         default:
            return null;
      }
   }

org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration

@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
   /*
   * 明顯是創建事務切面實例 BeanFactoryTransactionAttributeSourceAdvisor
   * */
   @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
   @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
   public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
      BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
      advisor.setTransactionAttributeSource(transactionAttributeSource());
      //設置通知類
      advisor.setAdvice(transactionInterceptor());
      if (this.enableTx != null) {
         advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
      }
      return advisor;
   }
   @Bean
   @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
   public TransactionAttributeSource transactionAttributeSource() {
      return new AnnotationTransactionAttributeSource();
   }
   /*
   * 創建事務advice  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;
   }
}

2.2、創建事務advice

org.springframework.transaction.interceptor.TransactionInterceptor

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {

@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
   Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
   // Adapt to TransactionAspectSupport's invokeWithinTransaction...
   return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}

org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
      final InvocationCallback invocation) throws Throwable {
   // If the transaction attribute is null, the method is non-transactional.
   //獲取事務屬性類 AnnotationTransactionAttributeSource
   TransactionAttributeSource tas = getTransactionAttributeSource();

//獲取方法上面有@Transactional註解的屬性
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);

3、事務註解解析@Transactional

這個方法就會掃描method上面的@Transactional註解,把註解裏面配置的屬性封裝到對象中,對應的對象是:RuleBasedTransactionAttribute,獲取方法上面有@Transactional註解的屬性,

3.1、獲取方法上面有@Transactional註解的屬性方法入口:

//獲取方法上面有@Transactional註解的屬性
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);

org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute

// 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);
}

org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#computeTransactionAttribute

@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
   // Don't allow no-public methods as required.
   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);
   // First try is the method in the target class.
   TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
   if (txAttr != null) {
      return txAttr;
   }

org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#findTransactionAttribute(java.lang.reflect.Method)

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

3.2、this.annotationParsers說明

org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#determineTransactionAttribute

private final Set<TransactionAnnotationParser> annotationParsers;

public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
   this.publicMethodsOnly = publicMethodsOnly;
   if (jta12Present || ejb3Present) {
      this.annotationParsers = new LinkedHashSet<>(4);
      //主要是用這個註解解析器,解析方法上面的@Transactional註解
      this.annotationParsers.add(new SpringTransactionAnnotationParser());
      if (jta12Present) {
         this.annotationParsers.add(new JtaTransactionAnnotationParser());
      }
      if (ejb3Present) {
         this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
      }
   }else {
      this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
   }
}

通過SpringTransactionAnnotationParser解析方法上面的@Transactional註解

 

org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement)

public class SpringTransactionAnnotationParser implements TransactionAnnotationParser, Serializable {
   @Override
   @Nullable
   public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
      AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
            element, Transactional.class, false, false);
      if (attributes != null) {
         return parseTransactionAnnotation(attributes);
      }else {
         return null;
      }
   }

3.3、註解解析方法parseTransactionAnnotation分析

org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(org.springframework.core.annotation.AnnotationAttributes)

對象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"));
   List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
   for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
      rollbackRules.add(new RollbackRuleAttribute(rbRule));
   }
   for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
      rollbackRules.add(new RollbackRuleAttribute(rbRule));
   }
   for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
      rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
   }
   for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
      rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
   }
   rbta.setRollbackRules(rollbackRules);

   return rbta;
}

4、開啓事務源碼分析

4.1、開啓事務代碼入口

org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);

org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary

@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
      final InvocationCallback invocation) throws Throwable {
   // If the transaction attribute is null, the method is non-transactional.
   //獲取事務屬性類 AnnotationTransactionAttributeSource
   TransactionAttributeSource tas = getTransactionAttributeSource();
   //獲取方法上面有@Transactional註解的屬性
   final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
   //獲取事務管理器
   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;
   }

4.2、進入方法createTransactionIfNecessary,分析開啓事務方法

org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary

//開啓事務,這裏重點看
status = tm.getTransaction(txAttr);

org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction

@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
   //這裏重點看,.DataSourceTransactionObject拿到對象
   Object transaction = doGetTransaction();
   // Cache debug flag to avoid repeated checks.
   boolean debugEnabled = logger.isDebugEnabled();
   if (definition == null) {
      // Use defaults if no transaction definition given.
      definition = new DefaultTransactionDefinition();
   }
   //第一次進來connectionHolder爲空的,所以不存在事務
   if (isExistingTransaction(transaction)) {
      // Existing transaction found -> check propagation behavior to find out how to behave.
      return handleExistingTransaction(definition, transaction, debugEnabled);
   }
   // Check definition settings for new transaction.
   if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
      throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
   }
   // No existing transaction found -> check propagation behavior to find out how to proceed.
   if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
      throw new IllegalTransactionStateException(
            "No existing transaction found for transaction marked with propagation 'mandatory'");
   }
   //第一次進來大部分會走這裏
   else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
         definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
         definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
      //先掛起
      SuspendedResourcesHolder suspendedResources = suspend(null);
         if (debugEnabled) {
            logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
         }
         try {
            boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
            //創建事務狀態對象,其實就是封裝了事務對象的一些信息,記錄事務狀態的
            DefaultTransactionStatus status = newTransactionStatus(
                  definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
            //開啓事務,重點看看 DataSourceTransactionObject
            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);
   }
}

這個方法創建事務對象,事務對象往往需要跟連接掛鉤,所以裏面肯定會有連接對象 ConnectionHolder,在這個方法裏面會首先從ThreadLocal中獲取連接對象,如下:

4.3、方法doGetTransaction分析

org.springframework.jdbc.datasource.DataSourceTransactionManager#doGetTransaction

@Override
protected Object doGetTransaction() {
   //管理connection對象,創建回滾點,按照回滾點回滾,釋放回滾點
   DataSourceTransactionObject txObject = new DataSourceTransactionObject();
   //DataSourceTransactionManager默認是允許嵌套事務的
   txObject.setSavepointAllowed(isNestedTransactionAllowed());
   //obtainDataSource() 獲取數據源對象,其實就是數據庫連接塊對象第一次進來爲null
   ConnectionHolder conHolder =
         (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
   txObject.setConnectionHolder(conHolder, false);
   return txObject;
}

這個ThreadLocal中value封裝了一個map,map是數據源對象DataSource和連接對象的映射關係,也就是說,如果上一個事務中建立了映射關係,下一個事務就可以通過當前線程從ThreadLocal中獲取到這個map,然後根據當前使用的數據源對象拿到對應的連接對象,然後設置到事務對象中。

4.4、根據connectionHolder對象判斷當前是否存在事務

事務和連接是異議綁定的,數據庫連接又與用戶請求回話綁定。

第一次進來connectionHolder爲空的,所以不存在事務:

 

第二次進來connectionHolder不爲空:

 

當方法Object transaction = doGetTransaction();執行完後,往下走:

//第一次進來connectionHolder爲空的,所以不存在事務
if (isExistingTransaction(transaction)) {
   // Existing transaction found -> check propagation behavior to find out how to behave.
   return handleExistingTransaction(definition, transaction, debugEnabled);
}

該方法判斷當前是否存在事務,如果能從事務對象中拿到連接對象,就表示當前是存在事務的。如果不存在,也就是說是第一次創建事務。則往下走:

//第一次進來大部分會走這裏
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
      definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
      definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
   //先掛起
   SuspendedResourcesHolder suspendedResources = suspend(null);
      if (debugEnabled) {
         logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
      }
      try {
         boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
         //創建事務狀態對象,其實就是封裝了事務對象的一些信息,記錄事務狀態的
         DefaultTransactionStatus status = newTransactionStatus(
               definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
         //開啓事務,重點看看 DataSourceTransactionObject
         doBegin(transaction, definition);
         //開啓事務後,改變事務狀態
         prepareSynchronization(status, definition);
         return status;
   }

後續源碼分析詳見第六章。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章