關於spring事務源碼的一些小理解

一、spring事務的簡單概述

因爲實現事務功能的方式各不相同,Spring進行了統一的抽象,造成了PlatformTransactionManager事務管理器頂級接口(平臺事務管理器),事務的提交、回滾等操做所有交給它來實現mysql

先來看下三大接口web

  • PlatformTransactionManager : 事務管理器spring

  • TransactionDefinition : 事務的一些基礎信息,如超時時間、隔離級別、傳播屬性等sql

  • TransactionStatus : 事務的一些狀態信息,如是不是一個新的事務、是否已被標記爲回滾數據庫

2PlatformTransactionManager

相關類方法:springboot

public interface PlatformTransactionManager {
  //獲取事務狀態
   TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
   //事務提交
   void commit(TransactionStatus status) throws TransactionException;
   //事務回滾
   void rollback(TransactionStatus status) throws TransactionException;

}複製代碼

繼承關係:bash

PlatformTransactionManager

AbstractPlatformTransactionManager
  DataSourceTransactionManager(重點)
  HibernateTransactionManager
  JpaTransactionManager複製代碼

觸發不一樣的事物管理器ide

springboot對PlatformTransactionManager的默認配置實現(引用spring-boot-starter-web中jdbc相關jarspring-boot

public class DataSourceTransactionManagerAutoConfiguration {

   @Configuration
   @ConditionalOnSingleCandidate(DataSource.class)
   static class DataSourceTransactionManagerConfiguration {

      private final DataSource dataSource;

      private final TransactionManagerCustomizers transactionManagerCustomizers;

      DataSourceTransactionManagerConfiguration(DataSource dataSource,
            ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
         this.dataSource = dataSource;
         this.transactionManagerCustomizers = transactionManagerCustomizers
               .getIfAvailable();
      }

      @Bean
      @ConditionalOnMissingBean(PlatformTransactionManager.class)
      public DataSourceTransactionManager transactionManager(
            DataSourceProperties properties) {
         DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(
               this.dataSource);
         if (this.transactionManagerCustomizers != null) {
            this.transactionManagerCustomizers.customize(transactionManager);
         }
         return transactionManager;
      }

   }

}複製代碼

經過@ConditionalOnMissingBean(PlatformTransactionManager.class)這個註解能夠直到若是沒有手動配置ui

PlatformTransactionManager即便用默認的子類DataSourceTransactionManager來管理實務


三、事務傳播特性和隔離級別

public interface TransactionDefinition {
事務傳播特性:
一、支持事務,若是當前線程沒有事務,新建一個事務
  int PROPAGATION_REQUIRED = 0;
二、支持事務,若是當前線程沒有事務,則以非事務執行
  int PROPAGATION_SUPPORTS = 1;
三、 當前若是有事務,Spring就會使用該事務;不然會拋出異常
  int PROPAGATION_MANDATORY = 2;
四、若是當前線程存在事務,或者不存在事務,都會新建一個事務,而且新建事務與當前事務是相互隔離的,若是新建事務執行時,會先將當前事務掛起,等新建事務執行完成後,再將放行當前事務,若是新事物出現異常,會正常回滾,但不會影響當前事務
  int PROPAGATION_REQUIRES_NEW = 3;
五、 不支持事務,若是存在事務,則會將當前事務掛起,以非事務執行
  int PROPAGATION_NOT_SUPPORTED = 4;
六、不支持事務,若是當前線程存在事務,將會拋異常
  int PROPAGATION_NEVER = 5;
七、若是當前線程存在事務,則新建一個回滾點,若是出現異常,則會回滾到上一個回滾點,對於當前事務是不受任何影響的。
  int PROPAGATION_NESTED = 6;
//隔離級別:默認的隔離級別(對mysql數據庫來講就是ISOLATION_ READ_COMMITTED,能夠重複讀)
  int ISOLATION_DEFAULT = -1;
//隔離級別:讀未提交
  int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
//隔離級別:讀已提交
  int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
//隔離級別:可重複讀
  int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
//隔離級別:序列化  
int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
   int TIMEOUT_DEFAULT = -1;
  int getPropagationBehavior();
   int getIsolationLevel();
   int getTimeout();
  boolean isReadOnly();
  @Nullable
  String getName();


}


複製代碼

四、爲何說spring事務是aop的一種實現

finishBeanFactoryInitialization(beanFactory);一路向後debug最後能夠看到下面的代碼
複製代碼
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
   if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
      return bean;
   }
   if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
      return bean;
   }
   if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
      this.advisedBeans.put(cacheKey, Boolean.FALSE);
      return bean;
   }

   // Create proxy if we have advice.
   //這裏就是獲取須要代理的類(若是存在advice)複製代碼
//獲取bean對應的advice集合。   
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
   if (specificInterceptors != DO_NOT_PROXY) {
      this.advisedBeans.put(cacheKey, Boolean.TRUE);
    //將獲取到的advice集合保存到代理對象中並返回。
      Object proxy = createProxy(
            bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
      this.proxyTypes.put(cacheKey, proxy.getClass());
      return proxy;
   }

   this.advisedBeans.put(cacheKey, Boolean.FALSE);
   return bean;
}複製代碼
這裏是建立代理的方法
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
      @Nullable Object[] specificInterceptors, TargetSource targetSource) {

   if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
      AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
   }

   ProxyFactory proxyFactory = new ProxyFactory();
   proxyFactory.copyFrom(this);

   if (!proxyFactory.isProxyTargetClass()) {
      if (shouldProxyTargetClass(beanClass, beanName)) {
         proxyFactory.setProxyTargetClass(true);
      }
      else {
         evaluateProxyInterfaces(beanClass, proxyFactory);
      }
   }
   //將advice封裝到 advisors中
   Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
   proxyFactory.addAdvisors(advisors);
    //這裏的targetSource就是目標對象,在後面調用的時候會用到
   proxyFactory.setTargetSource(targetSource);
   customizeProxyFactory(proxyFactory);
   proxyFactory.setFrozen(this.freezeProxy);
   if (advisorsPreFiltered()) {
      proxyFactory.setPreFiltered(true);
   }

   return proxyFactory.getProxy(getProxyClassLoader());
}


specificInterceptors是攔截器(若是是aop則是前置後置這些過濾器,若是是事務,則是事務攔截器)
BeanFactoryCacheOperationSourceAdvisor(保存了加強的信息)切面記錄是前置,後置等加強攔截器鏈而事務相關記錄的是事務攔截器private final Map<Object, TransactionAttribute> attributeCache = new ConcurrentHashMap<>(1024);保存方法對應的事務信息private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>(256);保存這個bean是否爲加強beanif (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {  return bean;}判斷這個bean是否爲代理類,若是不是直接返回單例和多例的區別:
protected void addSingleton(String beanName, Object singletonObject) {  synchronized (this.singletonObjects) {     this.singletonObjects.put(beanName, singletonObject);     this.singletonFactories.remove(beanName);     this.earlySingletonObjects.remove(beanName);     this.registeredSingletons.add(beanName);  }}將獲取到的bean保存到singletonObjects中private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);在每次調用的時候,直接從singletonObjects這個ConcurrentHashMap中獲取便可。若是是Prototype在從走一遍單例的流程else if (mbd.isPrototype()) {  // It's a prototype -> create a new instance. Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}複製代碼

五、事務方法調用

和aop調用同樣,最後會調用TransactionInterceptor的invock方法

public Object invoke(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);

   // Adapt to TransactionAspectSupport's invokeWithinTransaction... return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed); }複製代碼

而後會調用父類TransactionAspectSupportinvokeWithinTransaction方法

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

   // If the transaction attribute is null, the method is non-transactional.
   TransactionAttributeSource tas = getTransactionAttributeSource();
   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;
   }

   else {
      final ThrowableHolder throwableHolder = new ThrowableHolder();

      // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in. try { Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, 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; } } }複製代碼
相關文章
相關標籤/搜索