最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring的事務(wù)管理之聲明式事務(wù)詳解

 更新時間:2026年05月16日 10:42:54   作者:埃澤漫筆  
本文介紹了Spring中的事務(wù)管理,包括聲明式事務(wù)管理和和編程式事務(wù)管理,重點講解了聲明式事務(wù)管理和Spring AOP的關(guān)系,及Spring事務(wù)攔截器TransactionInterceptor的調(diào)用的,最后還釋了Spring事務(wù)的創(chuàng)建和使用的具體過程,以及解決了一些事務(wù)相關(guān)問題

Spring的事務(wù)管理介紹

在Spring中,事務(wù)也是用 AOP 切面技術(shù)來實現(xiàn)的,有兩種實現(xiàn)方式:

  • 聲明式事務(wù)管理: 基于Spring AOP實現(xiàn)。其本質(zhì)是對方法前后進(jìn)行攔截,然后在目標(biāo)方法開始之前創(chuàng)建或者加入一個事務(wù),在執(zhí)行完目標(biāo)方法之后根據(jù)執(zhí)行情況提交或者回滾事務(wù)。
  • 編程式事務(wù)管理: 編程式事務(wù)管理使用TransactionTemplate可實現(xiàn)更細(xì)粒度的事務(wù)控制。

聲明式事務(wù)管理不需要入侵代碼,通過@Transactional就可以進(jìn)行事務(wù)操作,更快捷而且簡單且大部分業(yè)務(wù)都可以滿足,推薦使用。

其實不管是編程式事務(wù)還是聲明式事務(wù),最終調(diào)用的底層核心代碼是一致的。

聲明式事務(wù)管理

1、 首先創(chuàng)建一個配置類,通過@EnableTransactionManagement開啟事務(wù)管理功能

@Component
@EnableTransactionManagement(proxyTargetClass = false)
@MapperScan(basePackages = {"com.xiangxue.jack.dao"},annotationClass = Repository.class)
public class EnableTransactionManagementBean {
   /*
    *  以下兩個@Bean的配置都可以設(shè)置數(shù)據(jù)源
    *  通過SqlSessionFactoryBean設(shè)置數(shù)據(jù)源
    */
    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean;
    }
   /*
    *  通過事務(wù)管理平臺的方式設(shè)置數(shù)據(jù)源
    */
    @Bean
    public PlatformTransactionManager annotationDrivenTransactionManager(DataSource dataSource) {
        DataSourceTransactionManager dtm = new DataSourceTransactionManager();
        dtm.setDataSource(dataSource);
        return dtm;
    }
}

2、定義數(shù)據(jù)源

@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;
    @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;
    }
}
jdbc.driverClassName = org.gjt.mm.mysql.Driver
jdbc.url = jdbc:mysql://127.0.0.1:3306/consult
jdbc.username = root
jdbc.password = 123456

知識點

數(shù)據(jù)源和事務(wù)管理平臺的加載都是在類ProxyTransactionManagementConfiguration中進(jìn)行的。Spring中的事務(wù)就是由 connection對象控制的,所以connection對象是和事務(wù)是綁定的,然后用戶請求過來時又需要數(shù)據(jù)庫連接來執(zhí)行 sql 語句, 所以用戶請求線程又是跟 connection 是綁定的。

開啟事務(wù)注解解析流程

首先看以下@EnableTransactionManagement注解的源碼

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
	// proxyTargetClass = false 表示是JDK動態(tài)代理支持接口代理。
	// true表示是Cglib代理支持子類繼承代理。
	boolean proxyTargetClass() default false;
	// 事務(wù)通知模式(切面織入方式),默認(rèn)代理模式(同一個類中方法互相調(diào)用攔截器不會生效)
	AdviceMode mode() default AdviceMode.PROXY;
	// 連接點上有多個通知時,排序,默認(rèn)最低。值越大優(yōu)先級越低。
	int order() default Ordered.LOWEST_PRECEDENCE;
}

進(jìn)入TransactionManagementConfigurationSelector

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
	@Override
	protected String[] selectImports(AdviceMode adviceMode) {
		/**
		 *  TODO : 導(dǎo)入需要加載的類
		 *  1、AutoProxyRegistrar: 給容器中注冊一個InfrastructureAdvisorAutoProxyCreator(Spring事務(wù)入口類) 組件;
		 *  利用后置處理器機(jī)制在對象創(chuàng)建以后,包裝對象,返回一個代理對象(增強(qiáng)器),
		 *  代理對象執(zhí)行方法利用攔截器鏈進(jìn)行調(diào)用;
		 *
		 *  2、ProxyTransactionManagementConfiguration: 就是一個配置類,定義了事務(wù)增強(qiáng)器、攔截器。
		 *
		 */
		switch (adviceMode) {
			case PROXY:
				// 重點看這2個類:
				// AutoProxyRegistrar
				// ProxyTransactionManagementConfiguration
				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);
	}
}

那么這個@EnableTransactionManagement開啟事務(wù)管理配置的注解是如何被調(diào)用的呢?我們回顧一下Spring的初始化核心流程

Spring 初始化核心流程回顧

spring容器初始化的核心方法AbstractApplicationContext#refresh ,

  • ├─ refresh Spring 初始化核心流程入口
  • │ ├─ prepareRefresh ① 準(zhǔn)備此上下文用于刷新,設(shè)置啟動時間和active標(biāo)志,初始化屬性
  • │ ├─ obtainFreshBeanFactory ② 創(chuàng)建 BeanFactory
  • │ ├─ prepareBeanFactory ③ 設(shè)置 BeanFactory 的基本屬性
  • │ ├─ postProcessBeanFactory ④ 子類處理自定義的BeanFactoryPostProcess
  • │ ├─ invokeBeanFactoryPostProcessors ⑤ 開啟事務(wù)管理配置的調(diào)用入口
  • │ ├─ registerBeanPostProcessors ⑥ 注冊攔截Bean創(chuàng)建的Bean處理器
  • │ ├─ initMessageSource ⑦ 初始化上下文中的資源文件,如國際化文件的處理等
  • │ ├─ initApplicationEventMulticaster ⑧ 初始化上下文的事件傳播器
  • │ ├─ onRefresh ⑨ 給子類擴(kuò)展初始化其他Bean,springboot 中用來做內(nèi)嵌 tomcat 啟動
  • │ ├─ registerListeners ⑩ 在所有bean中查找監(jiān)聽 bean,然后注冊到廣播器中
  • │ ├─ finishBeanFactoryInitialization ? 初始化所有的單例Bean、ioc、BeanPostProcessor的執(zhí)行、Aop入口
  • │ └─ finishRefresh ? 完成刷新過程,發(fā)布相應(yīng)的事件

進(jìn)入invokeBeanFactoryPostProcessors() 方法

類文件: org.springframework.beans.factory.support.AbstractApplicationContext

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// 看這個 invokeBeanFactoryPostProcessors 方法
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
		if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}
	}

進(jìn)入invokeBeanFactoryPostProcessors() 方法

類文件: org.springframework.beans.factory.support.PostProcessorRegistrationDelegate

public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
   /** ...... 省略 ......  **/
   /**
    * 調(diào)用過程
    * 在這里典型的 BeanDefinitionRegistryPostProcessor 就是 ConfigurationClassPostProcessor
    * 用于進(jìn)行bean定義的加載 比如我們的包掃描,@import等
    * @EnableAspectJAutoProxy 注解中的 AspectJAutoProxyRegistrar 類就是通過此方法調(diào)用執(zhí)行
    * @EnableTransactionManagement 注解中的 TransactionManagementConfigurationSelector 類就是通過此方法調(diào)用執(zhí)行
    */
	invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
	// 調(diào)用完之后,馬上clear
	currentRegistryProcessors.clear();			
}

進(jìn)入invokeBeanDefinitionRegistryPostProcessors() 方法

類文件: org.springframework.beans.factory.support.PostProcessorRegistrationDelegate

private static void invokeBeanDefinitionRegistryPostProcessors(
			Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
		for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
			// 重點看這個方法
			postProcessor.postProcessBeanDefinitionRegistry(registry);
		}
	}

進(jìn)入postProcessBeanDefinitionRegistry() 方法

所在類 org.springframework.context.annotation.ConfigurationClassPostProcessor

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
		int registryId = System.identityHashCode(registry);
		if (this.registriesPostProcessed.contains(registryId)) {
			throw new IllegalStateException(
					"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
		}
		if (this.factoriesPostProcessed.contains(registryId)) {
			throw new IllegalStateException(
					"postProcessBeanFactory already called on this post-processor against " + registry);
		}
		this.registriesPostProcessed.add(registryId);
		// 重點看這個方法
		processConfigBeanDefinitions(registry);
	}

知識點

ConfigurationClassPostProcessor類非常重要,此類是對Spring容器中所有的BeanDefinition的新增、修改等操作,也就是說對BeanDefinition的增刪查改都會在ConfigurationClassPostProcessor類中進(jìn)行。同時還支持了@Import、@ImportResource、@ComponetScan、@Configruration等注解的解析工作。

進(jìn)入processConfigBeanDefinitions() 方法,這個時候bean還沒有實例化

類文件: org.springframework.beans.factory.support.ConfigurationClassPostProcessor

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	 /** ...... 省略 ......  **/
	do {
			// 進(jìn)入parse方法
			parser.parse(candidates);
			parser.validate();
	}
	while (!candidates.isEmpty());
}

接下來的調(diào)用的過程較為繁瑣,此處省略無關(guān)的源碼,按照如下步驟自行跟蹤源碼即可

  • 進(jìn)入parse方法,
  • 進(jìn)入子parse方法,
  • 進(jìn)入processConfigurationClass方法,
  • 進(jìn)入doProcessConfigurationClass方法,
  • 最后進(jìn)入processImports 方法,

類文件: org.springframework.beans.factory.support.ConfigurationClassParser 到此處,selectImports()方法最終會被ConfigurationClassParser類的processImports()方法調(diào)用執(zhí)行,具體見第ConfigurationClassParser類的第569行,

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
			Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
	 /** ...... 省略 ......  **/
	if (candidate.isAssignable(ImportSelector.class)) {
	// Candidate class is an ImportSelector -> delegate to it to determine imports
	Class<?> candidateClass = candidate.loadClass();
	// 反射拿到 ImportSelector 接口類的實例化對象 selector
	ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
	ParserStrategyUtils.invokeAwareMethods(
			selector, this.environment, this.resourceLoader, this.registry);
	if (selector instanceof DeferredImportSelector) {
		this.deferredImportSelectorHandler.handle(
				configClass, (DeferredImportSelector) selector);
	}
	else {
	/*
	 * 然后通過 selector調(diào)用其實現(xiàn)類 AdviceModeImportSelector
	 * 的selectImports方法,模板中的鉤子方法。最后拿到返回的
	 * TransactionManagementConfigurationSelector的selectImports
	 * 方法返回的兩個類:
	 *  1、AutoProxyRegistrar.class
	 *  2、ProxyTransactionManagementConfiguration.class
     *  繼續(xù)遞歸調(diào)用當(dāng)前的 processImports 方法
     */
		String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
		Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
		processImports(configClass, currentSourceClass, importSourceClasses, false);
	}
}
    }

開啟事務(wù)的入口類

進(jìn)入selectImports()方法,找到其實現(xiàn)類AdviceModeImportSelectorselectImports方法

類文件: org.springframework.context.annotation.AdviceModeImportSelector

public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
		Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
		Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector");
		AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
		if (attributes == null) {
			throw new IllegalArgumentException(String.format(
					"@%s is not present on importing class '%s' as expected",
					annType.getSimpleName(), importingClassMetadata.getClassName()));
		}
		AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName());
		// 此方法最終會調(diào)用TransactionManagementConfigurationSelector
		// 的 selectImports方法
		String[] imports = selectImports(adviceMode);
		if (imports == null) {
			throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode);
		}
		return imports;
	}

調(diào)回到selectImports方法后,會把AutoProxyRegistrarProxyTransactionManagementConfiguration兩個類注冊到Beandefinition

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
	@Override
	protected String[] selectImports(AdviceMode adviceMode) {
		/**
		 *  TODO : 導(dǎo)入需要加載的類
		 *  1、AutoProxyRegistrar: 給容器中注冊一個InfrastructureAdvisorAutoProxyCreator 組件;
		 *  利用后置處理器機(jī)制在對象創(chuàng)建以后,包裝對象,返回一個代理對象(增強(qiáng)器),
		 *  代理對象執(zhí)行方法利用攔截器鏈進(jìn)行調(diào)用;
		 *
		 *  2、ProxyTransactionManagementConfiguration: 就是一個配置類,定義了事務(wù)增強(qiáng)器、攔截器。
		 *
		 */
		switch (adviceMode) {
			case PROXY:
				// 重點看這2個類:
				// AutoProxyRegistrar
				// ProxyTransactionManagementConfiguration
				return new String[] {AutoProxyRegistrar.class.getName(),
						ProxyTransactionManagementConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {determineTransactionAspectClass()};
			default:
				return null;
		}
	}
}

事務(wù)核心類 - AutoProxyRegistrar 源碼

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		boolean candidateFound = false;
		// 循環(huán)遍歷導(dǎo)入類上使用的所有注解(主要處理注解中有 mode和 proxyTargetClass屬性的)
		Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
		for (String annoType : annoTypes) {
			AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
			if (candidate == null) {
				continue;
			}
			// 獲取注解中的 mode 屬性
			Object mode = candidate.get("mode");
			// 獲取注解中的 proxyTargetClass 屬性
			Object proxyTargetClass = candidate.get("proxyTargetClass");
			if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
					Boolean.class == proxyTargetClass.getClass()) {
				candidateFound = true;
				// 如果 mode 是代理模式
				if (mode == AdviceMode.PROXY) {
					// 注冊事務(wù)AOP的入口類 InfrastructureAdvisorAutoProxyCreator,實際上這個AOP入口類起不了作用
					AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
					if ((Boolean) proxyTargetClass) {
						AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
						return;
					}
				}
			}
		}
	}

事務(wù)核心類 - ProxyTransactionManagementConfiguration 源碼

@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	//
	/**
	 * TODO : 定義事務(wù)增強(qiáng)器(事務(wù)織入)
	 *
	 * 定義了一個 advisor,設(shè)置事務(wù)屬性、設(shè)置事務(wù)攔截器 TransactionInterceptor、設(shè)置順序。
	 * 核心就是事務(wù)攔截器 TransactionInterceptor。
	 */
	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)
	// 主要負(fù)責(zé)解析 @Transactional注解里的屬性資源
	// 并包裝為 TransactionAttribute 類型
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	// 定義事務(wù)攔截器
	public TransactionInterceptor transactionInterceptor() {
		// TransactionInterceptor 實現(xiàn)了 MethodInterceptor 接口,
		// 在鏈?zhǔn)秸{(diào)用中會自動調(diào)用它的 invoke 方法
		TransactionInterceptor interceptor = new TransactionInterceptor();
		// 設(shè)置 TransactionAttribute 屬性
		interceptor.setTransactionAttributeSource(transactionAttributeSource());
		// 如果當(dāng)前事務(wù)管理器不為空,設(shè)置當(dāng)前事務(wù)管理器到攔截器中
		// 事務(wù)管理器和數(shù)據(jù)源綁定,此處可以自定義
		if (this.txManager != null) {
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}
}

知識點

此處可以參考父類AbstractTransactionManagementConfiguration中的setConfigurers方法,通過重寫TransactionManagementConfigurerannotationDrivenTransactionManager方法來自定義一個事務(wù)管理器。

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

到此為止,Spring中@EnableTransactionManagement注解的內(nèi)部注冊解析的準(zhǔn)備工作完成。

事務(wù)攔截器

TransactionInterceptor

Spring聲明式事物是基于AOP實現(xiàn)的,如果目標(biāo)方法存在事物則會對目標(biāo)對象進(jìn)行增強(qiáng)代理(JDK/Cglib)。而TransactionInterceptor則是事物體系中的增強(qiáng)器(Advise),它實現(xiàn)了MethodInterceptor接口,TransactionInterceptor會被封裝在使用了事務(wù)注解@Transactional的bean組件外面形成該組件的代理對象,當(dāng)調(diào)用相應(yīng)使用事務(wù)注解的方法時,TransactionInterceptorinvoke方法攔截器邏輯會被調(diào)用執(zhí)行,從而完成相應(yīng)的事務(wù)管理,包括:創(chuàng)建、提交和回滾等底層操作。

Spring 事務(wù)攔截處理流程

spring事務(wù)攔截器解析流程TransactionInterceptor#invoke ,

  • ├─ invoke Spring 事務(wù)攔截器入口
  • ├─ invokeWithinTransaction 調(diào)用Spring內(nèi)部事務(wù)
  • │ ├─ getTransactionAttributeSource ① 通過事務(wù)屬性源讀取事務(wù)的屬性配置
  • │ ├─ getTransactionAttribute ② 獲取該方法的事務(wù)屬性(傳播機(jī)制、隔離級別)
  • │ ├─ determineTransactionManager ③ 查找容器中的PlatformTransactionManager,用于管理事務(wù)
  • │ ├─ methodIdentification ④ 獲取被代理的類方法名稱
  • │ ├─ createTransactionIfNecessary ⑤ 創(chuàng)建事務(wù)并保存到TransactionInfo 聲明式事務(wù)
  • │ ├─ proceedWithInvocation ⑥ 火炬?zhèn)鬟f方法,攔截器鏈調(diào)用處理
  • │ ├─ completeTransactionAfterThrowing ⑦ 執(zhí)行業(yè)務(wù)報錯,回滾事務(wù)
  • │ ├─ cleanupTransactionInfo ⑧ 清空當(dāng)前事務(wù)信息,重置為老的
  • │ ├─ commitTransactionAfterReturning ⑨ 返回結(jié)果之前提交事務(wù)
  • │ ├─ execute ① 執(zhí)行實現(xiàn)TransactionCallback接口的doInTransaction回調(diào)方法 編程式事務(wù)
  • │ │ ├─ prepareTransactionInfo ② 準(zhǔn)備事務(wù)信息
  • │ │ │ ├─ new TransactionInfo ③ 創(chuàng)建事務(wù)信息對象
  • │ │ │ ├─ newTransactionStatus ④ 為事務(wù)信息對象設(shè)置事務(wù)狀態(tài)
  • │ │ │ └─ bindToThread ⑤ 把創(chuàng)建的事務(wù)信息對象和線程綁定到TreadLocal
  • │ │ ├─ proceedWithInvocation ⑥ 火炬?zhèn)鬟f方法, 攔截器鏈調(diào)用處理
  • │ │ ├─ rollbackOn ⑦ 事務(wù)是否滿足對異常進(jìn)行回滾處理條件
  • │ │ └─ cleanupTransactionInfo ⑧ 初始化所有的單例Bean、ioc、BeanPostProcessor的執(zhí)行、Aop入口

進(jìn)入invoke 方法,

類文件: org.springframework.transaction.interceptor.TransactionInterceptor

/**
	 *  TODO : 事務(wù)攔截器的攔截方法
	 * 事務(wù)攔截器TransactionInterceptor回調(diào)方法invoke通過調(diào)用TransactionAspectSupport事務(wù)切面支持類中的
	 * createTransactionIfNecessary和prepareTransactionInfo方法創(chuàng)建事務(wù)對象
	 */
	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.
		// 通過 AOP獲取事務(wù)的目標(biāo)類
		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
		// Adapt to TransactionAspectSupport's invokeWithinTransaction...
		// 核心方法,調(diào)用內(nèi)部事務(wù)處理,實際調(diào)用父類 TransactionAspectSupport的 invokeWithinTransaction方法
		return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
	}

進(jìn)入invokeWithinTransaction 方法,父類中實現(xiàn)

類文件: org.springframework.transaction.interceptor.TransactionAspectSupport

/**
 * TODO : 調(diào)用內(nèi)部事務(wù)
 */
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
			final InvocationCallback invocation) throws Throwable {
		// If the transaction attribute is null, the method is non-transactional.
		// 通過事務(wù)屬性源 TransactionAttributeSource讀取事務(wù)的屬性配置(名稱匹配)
		TransactionAttributeSource tas = getTransactionAttributeSource();
		// 獲取對應(yīng)事務(wù)屬性.如果事務(wù)屬性為空(則目標(biāo)方法不存在事務(wù))
		// 事務(wù)屬性源 NameMatchTransactionAttributeSource 的方法
		final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
		// 根據(jù)事務(wù)的屬性獲取 beanFactory 中的 PlatformTransactionManager (spring事務(wù)管理器的頂級接口),
		// 獲取 Spring事務(wù)管理IoC容器配置的事務(wù)處理器
		// 一般常用實現(xiàn)是 DataSourceTransactiuonManager
		final PlatformTransactionManager tm = determineTransactionManager(txAttr);
		// 目標(biāo)方法唯一標(biāo)識(類.方法,如service.ServiceImpl.add)
		// 獲取目標(biāo)類指定方法的事務(wù)連接點
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
		/*
		 * 區(qū)分不同類型的 PlatformTransactionManager事務(wù)處理器,不同類型的事務(wù)處理器調(diào)用方式不同。對
		 * CallbackPreferringPlatformTransactionManager,需要回調(diào)函數(shù)來實現(xiàn)事務(wù)的創(chuàng)建和提交,對非
		 * CallbackPreferringPlatformTransactionManager來說,則不需要使用回調(diào)函數(shù)來實現(xiàn)事務(wù)處理。
		 */
		// 如果txAttr為空或者tm 屬于非CallbackPreferringPlatformTransactionManager類型的事務(wù)處理器
		// 聲明式事務(wù)的操作
		if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
			// Standard transaction demarcation with getTransaction and commit/rollback calls.
			// 使用 getTransaction 和 提交/回滾 調(diào)用的標(biāo)準(zhǔn)事務(wù)劃分。
			// 創(chuàng)建事務(wù),將當(dāng)前事務(wù)狀態(tài)和信息保存到TransactionInfo對象中,重要
			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.
				// 這里就是一個環(huán)繞增強(qiáng),在這個proceed前后可以自己定義增強(qiáng)實現(xiàn)。
				// 回調(diào)方法執(zhí)行,執(zhí)行目標(biāo)方法(原有的業(yè)務(wù)邏輯)
				retVal = invocation.proceedWithInvocation();
			}
			catch (Throwable ex) {
				// target invocation exception
				// 根據(jù)事務(wù)定義的,該異常需要回滾就回滾,否則提交事務(wù)
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
				// 清空當(dāng)前事務(wù)信息,重置為老的
				cleanupTransactionInfo(txInfo);
			}
			// 返回結(jié)果之前提交事務(wù)
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}
		// 編程式事務(wù)
		// CallbackPreferringPlatformTransactionManager類型的事務(wù)處理器
		else {
			final ThrowableHolder throwableHolder = new ThrowableHolder();
			// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
			try {
				// 執(zhí)行實現(xiàn)T ransactionCallback 接口的 doInTransaction 回調(diào)方法
				Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> {
					TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
					try {
						// 攔截器鏈調(diào)用處理,使得最后目標(biāo)對象的方法得到調(diào)用
						return invocation.proceedWithInvocation();
					}
					catch (Throwable ex) {
						// 如果事務(wù)滿足對異常進(jìn)行回滾處理條件
						if (txAttr.rollbackOn(ex)) {
							// A RuntimeException: will lead to a rollback.
							// 如果異常是運行時異常,則事務(wù)回滾處理
							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;
						}
					}
					//清除當(dāng)前線程綁定的事務(wù)信息
					finally {
						cleanupTransactionInfo(txInfo);
					}
				}); // 到這里都是execute方法
				// Check result state: It might indicate a Throwable to rethrow.
				// 如果是ThrowableHolder類型的異常,則轉(zhuǎn)換為Throwable拋出,上拋異常
				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;
			}
		}
	}

進(jìn)入getTransactionAttribute 方法,父類中實現(xiàn)

類文件: org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource

public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
		if (method.getDeclaringClass() == Object.class) {
			return null;
		}
		// 首先看是否存在緩存值
		Object cacheKey = getCacheKey(method, targetClass);
		TransactionAttribute cached = this.attributeCache.get(cacheKey);
		if (cached != null) {
			// 如果緩存的是一個無事務(wù)對象,直接返回 null
			if (cached == NULL_TRANSACTION_ATTRIBUTE) {
				return null;
			}
			else {
				return cached;
			}
		}
		// 緩存中不存在
		else {
			// 重新計算 TransactionAttribute 屬性,根據(jù)方法和類的類型獲取事務(wù)信息
			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.isTraceEnabled()) {
					logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
				}
				// 將事務(wù)對象屬性放到緩存中,緩存的key與類的類型和方法相關(guān)
				this.attributeCache.put(cacheKey, txAttr);
			}
			return txAttr;
		}
	}

進(jìn)入computeTransactionAttribute 方法,父類中實現(xiàn)

類文件: org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource

protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
		// 如果被代理方法非public類型,則直接返回空,Spring事務(wù)不支持非public類型方法
		if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
			return null;
		}
		// 方法可能在接口上,但是我們需要目標(biāo)類的屬性。
		// 如果目標(biāo)類為空,則方法將保持不變。
		Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
		// First try is the method in the target class.
		// 解析方法上的 @Transactional 屬性
		TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
		if (txAttr != null) {
			return txAttr;
		}
		// Second try is the transaction attribute on the target class.
		// 如果方法上沒有事務(wù)屬性,就從類上來獲取
		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;
	}

知識點

被代理方法是否是public類型,就是在computeTransactionAttribute這個方法中進(jìn)行校驗的,Spring中的事務(wù)只對public類型的方法起作用,非public類型事務(wù)失效。

@Transactional注解的解析

  • 進(jìn)入findTransactionAttribute 方法,
  • 進(jìn)入determineTransactionAttribute 方法,
  • 進(jìn)入parseTransactionAnnotation 方法,

類文件: org.springframework.transaction.annotation.SpringTransactionAnnotationParser

/**
 * TODO : 解析事務(wù)注解中的屬性
 */
 protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
		RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
		// 獲取事務(wù)傳播屬性
		Propagation propagation = attributes.getEnum("propagation");
		rbta.setPropagationBehavior(propagation.value());
		// 獲取事務(wù)隔離等級
		Isolation isolation = attributes.getEnum("isolation");
		rbta.setIsolationLevel(isolation.value());
		// 獲取事務(wù)獲取事務(wù)超時時間
		rbta.setTimeout(attributes.getNumber("timeout").intValue());
		// 獲取事務(wù)是否只讀
		rbta.setReadOnly(attributes.getBoolean("readOnly"));
		// 獲取事務(wù)事務(wù)管理器 bean的名稱
		rbta.setQualifier(attributes.getString("value"));
		List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
		// 獲取事務(wù)回滾相關(guān)配置
		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;
	}

到此為止,@Transactional注解的加載工作也完成,注解的屬性值已近被加載到spring容器中了,接下來開始具體的事務(wù)操作過程。

事務(wù)的實現(xiàn)過程

創(chuàng)建事務(wù)之前的準(zhǔn)備工作已經(jīng)完成了,那么具體事務(wù)是如何創(chuàng)建實現(xiàn)的呢?

回到invokeWithinTransaction方法,

進(jìn)入createTransactionIfNecessary 方法,

類文件: org.springframework.transaction.interceptor.TransactionAspectSupport

/**
 * TODO : 根據(jù)給定的事務(wù)屬性創(chuàng)建事務(wù)對象
 */
 protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
			@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
		// 如果沒有指定名稱,則應(yīng)用方法標(biāo)識作為事務(wù)名稱。
		// 讀取事務(wù)方法調(diào)用的事務(wù)配置屬性
		if (txAttr != null && txAttr.getName() == null) {
			// 如果事務(wù)名稱為 null,則使用方法的名稱(事務(wù)連接點標(biāo)識)作為事務(wù)名稱,
			// 調(diào)用一個實現(xiàn) DelegatingTransactionAttribute 接口的匿名內(nèi)部類
			txAttr = new DelegatingTransactionAttribute(txAttr) {
				@Override
				// 使用方法名稱作為事務(wù)名稱
				public String getName() {
					return joinpointIdentification;
				}
			};
		}
		// 事務(wù)狀態(tài)封裝了事務(wù)執(zhí)行的狀態(tài)信息
		TransactionStatus status = null;
		if (txAttr != null) {
			if (tm != null) {
				// 事務(wù)處理器創(chuàng)建事務(wù),并且返回當(dāng)前事務(wù)的狀態(tài)信息
				// 核心方法,真正底層創(chuàng)建事務(wù)對象的方法
				status = tm.getTransaction(txAttr);
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
							"] because no transaction manager has been configured");
				}
			}
		}
		// 準(zhǔn)備事務(wù)信息,事務(wù)信息 TransactionInfo 封裝了事務(wù)配置和狀態(tài)信息
		return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
	}

進(jìn)入getTransaction 方法,

類文件: org.springframework.transaction.support.AbstractPlatformTransactionManager

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
		// doGetTransaction()方法是抽象方法,具體的實現(xiàn)由具體的事務(wù)處理器提供
		Object transaction = doGetTransaction();
		// Cache debug flag to avoid repeated checks.
		boolean debugEnabled = logger.isDebugEnabled();
		// 如果沒有配置事務(wù)屬性,則使用默認(rèn)的事務(wù)屬性
		if (definition == null) {
			// Use defaults if no transaction definition given.
			definition = new DefaultTransactionDefinition();
		}
		// 檢查當(dāng)前線程是否存在事務(wù),如果已存在事務(wù),那么需要根據(jù)在事務(wù)屬性中定義的事務(wù)傳播屬性來處理事務(wù)的產(chǎn)生(檢查傳播行為)
		if (isExistingTransaction(transaction)) {
			// Existing transaction found -> check propagation behavior to find out how to behave.
			// 處理已存在的事務(wù)的情況
			return handleExistingTransaction(definition, transaction, debugEnabled);
		}
		// Check definition settings for new transaction.
		// 檢查事務(wù)屬性中timeout超時屬性設(shè)置是否合理
		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.
		// 對事務(wù)屬性中配置的事務(wù)傳播特性處理
		// 如果當(dāng)前獲取不到存在的事務(wù),且事務(wù)傳播特性配置的是 mandatory,當(dāng)前沒有事務(wù)存在,拋出異常
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
			throw new IllegalTransactionStateException(
					"No existing transaction found for transaction marked with propagation 'mandatory'");
		}
		// 獲取不到存在的事務(wù),并且事務(wù)傳播屬性是 REQUIRED、REQUIRES_NEW、NESTED
		// 則執(zhí)行事務(wù)掛起,新建事務(wù)。
		else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
				definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			// 掛起當(dāng)前事務(wù)
			SuspendedResourcesHolder suspendedResources = suspend(null);
			if (debugEnabled) {
				logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
			}
			try {
				// 不激活和當(dāng)前線程綁定的事務(wù),因為事務(wù)傳播特性配置要求創(chuàng)建新的事務(wù)
				boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
				// 創(chuàng)建一個新的事務(wù)狀態(tài)
				DefaultTransactionStatus status = newTransactionStatus(
						definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
				// 核心方法:創(chuàng)建事務(wù)的調(diào)用,具體實現(xiàn)由具體的事務(wù)處理器提供。
				// 設(shè)置事務(wù)隔離級別(spring默認(rèn)的事務(wù)隔離級別是跟JDBC相同的,即默認(rèn)情況Spring不設(shè)置事務(wù)隔離級別);
				doBegin(transaction, definition);
				// 初始化和同步事務(wù)狀態(tài)
				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);
			}
			// 創(chuàng)建空事務(wù),針對 supported 類型的事務(wù)傳播特性,激活和當(dāng)前線程綁定的事務(wù)
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			// 準(zhǔn)備事務(wù)狀態(tài)
			return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
		}
	}

知識點

抽象事務(wù)管理器AbstractPlatformTransactionManager提供了創(chuàng)建事務(wù)的模板,這個模板會被具體的事 務(wù)處理器所使用,抽象事務(wù)管理器根據(jù)事務(wù)屬性配置和當(dāng)前線程綁定信息對事務(wù)是否需要創(chuàng)建以及如何創(chuàng)建進(jìn)行一 些通用的處理,然后把事務(wù)創(chuàng)建的底層細(xì)節(jié)交給具體的事務(wù)處理器實現(xiàn)。

進(jìn)入doGetTransaction 方法,由jdbc包下的數(shù)據(jù)源類實現(xiàn)

類文件: org.springframework.jdbc.datasource.DataSourceTransactionManager

protected Object doGetTransaction() {
		// 管理 connection對象,創(chuàng)建回滾點,按照回滾點回滾,釋放回滾點
		// DataSourceTransactionObject 就是真正的事務(wù)對象
		DataSourceTransactionObject txObject = new DataSourceTransactionObject();
		// DataSourceTransactionManager 默認(rèn)是允許嵌套事務(wù)的
		txObject.setSavepointAllowed(isNestedTransactionAllowed());
		// obtainDataSource() 獲取數(shù)據(jù)源對象,其實就是數(shù)據(jù)庫連接對象
		// ConnectionHolder 持有了 Connection,并對 Connection進(jìn)行了包裝
		ConnectionHolder conHolder =
				(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
		txObject.setConnectionHolder(conHolder, false);
		return txObject;
	}

進(jìn)入getResource方法,

類文件: org.springframework.transaction.support.TransactionSynchronizationManager

public static Object getResource(Object key) {
		// 查看數(shù)據(jù)源連接池有沒有擴(kuò)展,一般沒有
		Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
		Object value = doGetResource(actualKey);
		if (value != null && logger.isTraceEnabled()) {
			logger.trace("Retrieved value [" + value + "] for key [" + actualKey + "] bound to thread [" +
					Thread.currentThread().getName() + "]");
		}
		return value;
	}

進(jìn)入doGetResource方法,

類文件: org.springframework.transaction.support.TransactionSynchronizationManager

private static Object doGetResource(Object actualKey) {
		// 事務(wù)默認(rèn)傳播屬性會共用同一個連接,因此會去 ThreadLocal 中獲取連接,如果存在就直接返回
		// map對應(yīng)了當(dāng)前數(shù)據(jù)源對象和 當(dāng)前連接的綁定關(guān)系
		Map<Object, Object> map = resources.get();
		if (map == null) {
			return null;
		}
		Object value = map.get(actualKey);
		// Transparently remove ResourceHolder that was marked as void...
		if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
			map.remove(actualKey);
			// Remove entire ThreadLocal if empty...
			if (map.isEmpty()) {
				resources.remove();
			}
			value = null;
		}
		return value;
	}

執(zhí)行到doGetResource,也就說明了,事務(wù)的執(zhí)行默認(rèn)使用了同一個數(shù)據(jù)庫連接。

doGetTransaction 方法執(zhí)行完返回了事務(wù)對象,返回到getTransaction方法中

進(jìn)入doBegin方法

類文件: org.springframework.jdbc.datasource.DataSourceTransactionManager

protected void doBegin(Object transaction, TransactionDefinition definition) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		Connection con = null;
		try {
			// 如果沒有數(shù)據(jù)庫連接
			if (!txObject.hasConnectionHolder() ||
					txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
				// 從連接池里面獲取連接
				Connection newCon = obtainDataSource().getConnection();
				if (logger.isDebugEnabled()) {
					logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
				}
				// 把連接包裝成 ConnectionHolder,然后設(shè)置到事務(wù)對象中
				txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
			}
			txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
			con = txObject.getConnectionHolder().getConnection();
			// 從數(shù)據(jù)庫連接中獲取隔離級別,Mysql默認(rèn)隔離級別是 可重復(fù)讀
			Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
			txObject.setPreviousIsolationLevel(previousIsolationLevel);
			if (con.getAutoCommit()) {
				txObject.setMustRestoreAutoCommit(true);
				if (logger.isDebugEnabled()) {
					logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
				}
				// 關(guān)閉連接的自動提交,其實這步就是開啟了事務(wù)
				con.setAutoCommit(false);
			}
			// 設(shè)置只讀事務(wù) 從這一點設(shè)置的時間點開始(時間點a)到這個事務(wù)結(jié)束的過程中,
			// 其他事務(wù)所提交的數(shù)據(jù),該事務(wù)將看不見!
			// 設(shè)置只讀事務(wù)就是告訴數(shù)據(jù)庫,我這個事務(wù)內(nèi)沒有新增,修改,刪除操作
			// 只有查詢操作,不需要數(shù)據(jù)庫鎖等操作,減少數(shù)據(jù)庫壓力
			prepareTransactionalConnection(con, definition);
			// 自己提交關(guān)閉了,就說明已經(jīng)開啟事務(wù)了,事務(wù)是活動的
			txObject.getConnectionHolder().setTransactionActive(true);
			int timeout = determineTimeout(definition);
			if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
				txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
			}
			// Bind the connection holder to the thread.
			if (txObject.isNewConnectionHolder()) {
				// 如果是新創(chuàng)建的事務(wù),則建立當(dāng)前線程和數(shù)據(jù)庫連接的關(guān)系
				TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
			}
		}
		catch (Throwable ex) {
			if (txObject.isNewConnectionHolder()) {
				DataSourceUtils.releaseConnection(con, obtainDataSource());
				txObject.setConnectionHolder(null, false);
			}
			throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
		}
	}

doBegin方法中的 con.setAutoCommit(false)執(zhí)行完,正式開啟了Spring 事務(wù)管理功能。

事務(wù)問題匯總

問題一

AutoProxyRegistrar是AOP的入口類,之前@EnableAspectJAutoProxy也會通過AutoProxyRegistrar生成一個AOP的入口類,那么AOP的入口類會有兩個嗎?

參考答案

不會,Spring AOP創(chuàng)建的入口類名字默認(rèn)都叫org.springframework.aop.config.internalAutoProxyCreator,并且優(yōu)先級設(shè)置在AopConfigUtils類中:

static {
       // 事務(wù)代理 入口類優(yōu) 先級最低
		APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
		// XML代理 入口類 優(yōu)先級其次
		APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
		// AspectJ代理 入口類 優(yōu)先級最高
		APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
    }

由此可見,AspectJ的入口類AnnotationAwareAspectJAutoProxyCreator優(yōu)先級最高,也就是說如果設(shè)置了切面,那么入口類只會有AnnotationAwareAspectJAutoProxyCreator會起作用。

問題二

兩個方法上都使用了@Transactional默認(rèn)傳播屬性,內(nèi)部是如何保證使用了同一個連接的?

參考答案

事務(wù)默認(rèn)傳播屬性會共用同一個連接,內(nèi)部是通過ThreadLocal來保證連接的重復(fù)可用。默認(rèn)第一次肯定不會從Map中拿到連接,直接返回null,只有第二次進(jìn)來get()的值才不會為空。

private static Object doGetResource(Object actualKey) {
		// 事務(wù)默認(rèn)傳播屬性會共用同一個連接,因此會去 ThreadLocal 中獲取連接,
		// 如果存在就直接返回,否則創(chuàng)建新的連接
		// Map保存了當(dāng)前數(shù)據(jù)源對象 和 當(dāng)前連接的綁定關(guān)系
		Map<Object, Object> map = resources.get();
		if (map == null) {
			return null;
		}
		Object value = map.get(actualKey);
		// Transparently remove ResourceHolder that was marked as void...
		if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
			map.remove(actualKey);
			// Remove entire ThreadLocal if empty...
			if (map.isEmpty()) {
				resources.remove();
			}
			value = null;
		}
		return value;
	}

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Spring?代碼技巧梳理總結(jié)讓你愛不釋手

    Spring?代碼技巧梳理總結(jié)讓你愛不釋手

    這篇文章主要分享了Spring?代碼技巧梳理總結(jié),文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-06-06
  • SpringBoot中多環(huán)境啟動配置的教程詳解

    SpringBoot中多環(huán)境啟動配置的教程詳解

    在SpringBoot項目的生命周期中,存在不同的環(huán)境,我們就需要針對不同環(huán)境制定不同名稱的配置文件,里面放置不同環(huán)境下所需的配置項,下面小編就來和大家詳細(xì)講講SpringBoot如何進(jìn)行多環(huán)境啟動配置的吧
    2024-02-02
  • Mybatis攔截器實現(xiàn)數(shù)據(jù)權(quán)限的示例代碼

    Mybatis攔截器實現(xiàn)數(shù)據(jù)權(quán)限的示例代碼

    在我們?nèi)粘i_發(fā)過程中,通常會涉及到數(shù)據(jù)權(quán)限問題,本文主要介紹了Mybatis攔截器實現(xiàn)數(shù)據(jù)權(quán)限的示例代碼,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • java.sql.SQLException異常原因排查與解決

    java.sql.SQLException異常原因排查與解決

    在日常開發(fā)中,大家應(yīng)該或多或少都遇到SQL 在本地跑得好好的,一放到服務(wù)里執(zhí)行就報 java.sql.SQLException,本文將結(jié)合一個小 Demo,帶大家看一下 SQLException 的常見原因,以及如何一步步排查
    2025-09-09
  • java打包成jar并執(zhí)行jar包中指定的main方法

    java打包成jar并執(zhí)行jar包中指定的main方法

    這篇文章主要介紹了如何將java打包成可執(zhí)行的jar,并執(zhí)行jar包中指定的main方法的相關(guān)資料,文中給出了詳細(xì)的示例代碼,對大家具有一定的參考價值,需要的朋友們下面來一起看看吧。
    2017-03-03
  • 使用java + selenium + OpenCV破解騰訊防水墻滑動驗證碼功能

    使用java + selenium + OpenCV破解騰訊防水墻滑動驗證碼功能

    這篇文章主要介紹了使用java + selenium + OpenCV破解騰訊防水墻滑動驗證碼,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • java代碼規(guī)范review異常事故記錄

    java代碼規(guī)范review異常事故記錄

    這篇文章主要為大家介紹了java代碼規(guī)范關(guān)于異常review代碼發(fā)生異常的事故記錄,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • java求解集合的子集的實例

    java求解集合的子集的實例

    這篇文章主要介紹了 java求解集合的子集的實例的相關(guān)資料,希望通過本文能幫助到大家,讓大家掌握這樣的方法,需要的朋友可以參考下
    2017-10-10
  • spring @Transactional 無效的解決方案

    spring @Transactional 無效的解決方案

    這篇文章主要介紹了spring @Transactional 無效的解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • java實現(xiàn)音頻文件播放功能

    java實現(xiàn)音頻文件播放功能

    這篇文章主要為大家詳細(xì)介紹了java實現(xiàn)音頻文件播放功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-12-12

最新評論

石狮市| 临江市| 安溪县| 阿荣旗| 集安市| 定南县| 喀什市| 磐安县| 阿勒泰市| 景洪市| 偏关县| 乐陵市| 门源| 江西省| 平利县| 萝北县| 弋阳县| 明溪县| 内黄县| 林州市| 北宁市| 太仓市| 江阴市| 平阳县| 新民市| 密山市| 巴楚县| 蒙阴县| 保德县| 隆安县| 梁平县| 开封市| 泰来县| 岳普湖县| 麻栗坡县| 巧家县| 项城市| 新巴尔虎右旗| 达孜县| 土默特左旗| 皋兰县|