@Transactional 事务获取数据源的源码解析

news2025/1/11 11:04:23

spring在开启事务的时候是去拿数据源的,今天我们详细分析一下,@Transactional 事务获取数据源的源码解析:

1、从业务代码声明式事务开始:

接口调用到这里,原理是生成了动态代理类,默认是通过cglib实现的类:


 

2、来到 class CglibAopProxy implements AopProxy, Serializable

点进入:

public CglibMethodInvocation(Object proxy, @Nullable Object target, Method method,
				Object[] arguments, @Nullable Class<?> targetClass,
				List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {

			super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);//进入父类

			// Only use method proxy for public methods not derived from java.lang.Object
			this.methodProxy = (isMethodProxyCompatible(method) ? methodProxy : null);
		}

3、来到:public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable

点击

@Override
	@Nullable
	public Object invoke(MethodInvocation mi) throws Throwable {
		MethodInvocation oldInvocation = invocation.get();
		invocation.set(mi);
		try {
			return mi.proceed();//进入事务相关的类
		}
		finally {
			invocation.set(oldInvocation);
		}
	}

 又进入父类

然后来到了事务的拦截器:

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable 

 4、TransactionInterceptor 来到:

@Override
	@Nullable
	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...
        //进入父类 TransactionAspectSupport
		return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
			@Override
			@Nullable
			public Object proceedWithInvocation() throws Throwable {
				return invocation.proceed();//接口实现,父类一会会调用
			}
			@Override
			public Object getTarget() {
				return invocation.getThis();//接口实现,父类一会会调用
			}
			@Override
			public Object[] getArguments() {
				return invocation.getArguments();//接口实现,父类一会会调用
			}
		});
	}

5、来到:public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean

核心在这

 点击进入:

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

		// If no name specified, apply method identification as transaction name.
		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) {
               //PlatformTransactionManager tm 事务模板管理类,核心类
				status = tm.getTransaction(txAttr);//点击进入
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
							"] because no transaction manager has been configured");
				}
			}
		}
		return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
	}

点击显然进入第一个抽象类 

6、来到:public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable

@Override
	public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
			throws TransactionException {

		// Use defaults if no transaction definition given.
		TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());

		Object transaction = doGetTransaction();
		boolean debugEnabled = logger.isDebugEnabled();

		if (isExistingTransaction(transaction)) {
			// Existing transaction found -> check propagation behavior to find out how to behave.
			return handleExistingTransaction(def, transaction, debugEnabled);
		}

		// Check definition settings for new transaction.
		if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
			throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
		}

		// No existing transaction found -> check propagation behavior to find out how to proceed.
		if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
			throw new IllegalTransactionStateException(
					"No existing transaction found for transaction marked with propagation 'mandatory'");
		}
		else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			SuspendedResourcesHolder suspendedResources = suspend(null);
			if (debugEnabled) {
				logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
			}
			try {//核心处理,点击进入
				return startTransaction(def, transaction, debugEnabled, suspendedResources);
			}
			catch (RuntimeException | Error ex) {
				resume(null, suspendedResources);
				throw ex;
			}
		}
		else {
			// Create "empty" transaction: no actual transaction, but potentially synchronization.
			if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
				logger.warn("Custom isolation level specified but no actual transaction initiated; " +
						"isolation level will effectively be ignored: " + def);
			}
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
		}
	}

来到:

private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
			boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {

		boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
		DefaultTransactionStatus status = newTransactionStatus(
				definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
		doBegin(transaction, definition);//开始获取
		prepareSynchronization(status, definition);
		return status;
	}

点击看到实现子类

进入 public class DataSourceTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, InitializingBean

  7、来到 DataSourceTransactionManager

@Override
	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");
				}
				txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
			}

			txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
			con = txObject.getConnectionHolder().getConnection();

			Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
			txObject.setPreviousIsolationLevel(previousIsolationLevel);
			txObject.setReadOnly(definition.isReadOnly());

			// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
			// so we don't want to do it unnecessarily (for example if we've explicitly
			// configured the connection pool to set it already).
			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);
			}

			// Bind the connection holder to the thread.
			if (txObject.isNewConnectionHolder()) {
				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);
		}
	}

点击  obtainDataSource()

  //获取JDK原生的dataSource
  protected DataSource obtainDataSource() {
		DataSource dataSource = getDataSource();
		Assert.state(dataSource != null, "No DataSource set");
		return dataSource;
	}

点击:obtainDataSource().getConnection();

 发现很多的实现类。具体进入哪个连接池实现类,就要参考我们的服务配置,spring.dataSource.type 配置的哪个类,如果不配置springboot高版本默认是HikariDatasource 连接池类,当然也可以是自定义的连接池,处理一些自定义的业务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/76552.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《Linux运维实战:MongoDB数据库逻辑备份恢复(方案三)》

一、备份与恢复方案 Percona Backup for MongoDB 是一个开源、分布式和低影响的解决方案&#xff0c;用于MongoDB分片集群和副本集的一致备份&#xff0c;不支持单实例mongodb服务。从版本1.7.0开始&#xff0c;Percona Backup for MongoDB支持物理和逻辑备份和恢复&#xff0…

计算机网络—各层协议极其作用

文章目录应用层传输层网络层链路层物理层————————————————————————————————应用层 &#xff08;1&#xff09;应用层&#xff1a;直接为用户的应用进程提供服务。第三方自定义协议&#xff08;HTTP协议&#xff0c;支持电子邮件发送的SMTP协议…

Metal每日分享,LUT查找滤镜效果

本案例的目的是理解如何用Metal实现LUT颜色查找表滤镜&#xff0c;通过将颜色值存储在一张表中&#xff0c;在需要的时候通过索引在这张表上找到对应的颜色值&#xff0c;将原有色值替换成查找表中的色值; 总结就是一种针对色彩空间的管理和转换技术&#xff0c;LUT 就是一个 …

【MySQL】深入理解隔离性

文章目录多版本并发控制(MVCC)如何解决读-写并发undo 日志模拟MVCC过程select读取版本隔离性的实现为什么要有隔离级别快照(read view)可重复读(RR&#xff09;与读提交(RC&#xff09;的本质区别多版本并发控制(MVCC) 多版本并发控制(MVCC)是一种用来解决读写冲突的无锁并发控…

[附源码]计算机毕业设计教务管理系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

2023最新SSM计算机毕业设计选题大全(附源码+LW)之java银行管理系统275d1

要开始我们毕业设计的第一步的关键就是选好我们的课题&#xff0c;有的同学开始选题的时候想着按照传统的课题延续下去&#xff0c;在设计题目时&#xff0c;不要过于笼统广泛&#xff0c;选择题目其实并不难&#xff0c;要多从自身的角度出发&#xff0c;要结合你们当前所处的…

Briefings in Bioinformatics2021 | DLGN+:基于GAN和强化学习的分子从头双目标性质生成

论文标题&#xff1a;De novo generation of dual-target ligands using adversarial training and reinforcement learning 论文地址&#xff1a;https://academic.oup.com/bib/article/22/6/bbab333/6354720 代码&#xff1a;https://github.com/lllfq/DLGN 一、模型结构 …

数学基础从高一开始3、集合的基本运算

目录 复习内容&#xff1a; 并集的概念 你能用符号语言和图形语言表示并集这个集合吗? 例1:求并集 例2&#xff1a;求并集 符号解析&#xff1a; 例3&#xff1a; 交集的概念 例4&#xff1a; 例5&#xff1a; 例6&#xff1a; 思考题&#xff1a; 作业&#xff…

20221209在Ubuntu22.04下读取苹果分区APFS的步骤

20221209在Ubuntu22.04下读取苹果分区APFS的步骤 缘起&#xff1a;公司的新来的美工要清理MAC电脑。 由于忘记管理员密码&#xff1f;于是备份文件&#xff0c;重装系统&#xff01; 于是通过固态硬盘盒子将2TB的M2接口的固态硬盘SSD格式化为APFS&#xff0c;这样MAC电脑就可…

2022下半年软考成绩即将公布,预约查分提醒,查分快人一步

距离2022下半年考试已经过去一个多月了&#xff0c;大家都在焦急的等待软考成绩查询。根据往年情况来看&#xff0c;软考成绩查询时间并不是固定的一个时间点&#xff0c;不过可以大致预测下应该是在12月中/下旬左右开放成绩查询&#xff0c;具体情况以官方公告为准。 历年软考…

玩以太坊链上项目的必备技能(类型-引用类型-Solidity之旅三)

在前文我们讲述了值类型&#xff0c;也就说再修改值类型的时候&#xff0c;每次都有一个独立的副本&#xff0c;如&#xff1a;string 类型的状态变量&#xff0c;其值是无法修改&#xff0c;而是拷贝出一份该状态的变量&#xff0c;将新值存起来。对于处理稍微复杂地值类型时&…

2022最新性能测试面试题(带答案)

一、性能测试开展过程&#xff1a; 答&#xff1a;第一步&#xff1a;找产品沟通哪些接口需要压测&#xff0c;需要达到什么样的预期值(TPS和响应时间) 第二步&#xff1a;编写测试计划&#xff0c;人员、时间周期、工具 第三步&#xff1a;环境搭建 第四步&#xff1a;造数…

计算机操作系统

并行和并发的区别与联系&#xff1f; 【并发】 多个任务交替执行 计算机在运行过程中&#xff0c;有很多指令会涉及 I/O 操作&#xff0c;而 I/O 操作又是相当耗时的&#xff0c;速度远远低于 CPU&#xff0c;这导致 CPU 经常处于空闲状态&#xff0c;只能等待 I/O 操作完成后…

springboot项目如何启用arthas

Arthas 是Alibaba开源的Java诊断工具&#xff0c;深受开发者喜爱。当你遇到以下类似问题而束手无策时&#xff0c;Arthas可以帮助你解决&#xff1a; 这个类从哪个 jar 包加载的&#xff1f;为什么会报各种类相关的 Exception&#xff1f;我改的代码为什么没有执行到&#xff…

HTML网页设计:爱护动物题材——保护动物大象(6页) HTML网页设计结课作业 web课程设计网页规划与设计 网页设计成品DW静态网页

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

scConverter 文档转换 DLL / SDK

scConverter 转换 DLL / SDK scConverter 是一个DLL&#xff0c;可以将PDF、DWF、Gerber、CGM、TIFF、CALS、PLT、PNG和JPEG文件转换为大量输出格式。可用的输出格式列表包括Adob​​e PDF、PDF/A、DXF、DWF、CALS、TIFF、PLT和PNG。您将在下面找到所有可用输入和输出格式的完整…

R语言用向量自回归(VAR)进行经济数据脉冲响应研究分析

自从Sims&#xff08;1980&#xff09;发表开创性的论文以来&#xff0c;向量自回归模型已经成为宏观经济研究中的关键工具。最近我们被客户要求撰写关于向量自回归&#xff08;VAR&#xff09;的研究报告&#xff0c;包括一些图形和统计输出。这篇文章介绍了VAR分析的基本概念…

Java高级——后端编译与优化

后端编译与优化解释器和编译器编译器即时编译器分层编译热点代码热点探测计数器编译过程查看及分析即时编译结果提前编译器jaotc的提前编译后端编译优化总览优化演示方法内联&#xff08;最重要的优化技术之一&#xff09;逃逸分析&#xff08;最前沿的优化技术之一&#xff09…

15. 过拟合和欠拟合

1. 过拟合和欠拟合 当数据比较简单时&#xff0c;使用模型容量低的模型更好&#xff0c;否则使用高的会出现过拟合。如果是复杂的数据用到简单模型上会出现欠拟合&#xff0c;用到复杂模型上是正常的。 2. 模型容量 模型容量&#xff1a;拟合各种函数的能力 低容量的模型难以…

Springboot+Easyexcel:导出excel表格

常规导出 常规导出excel有两种&#xff0c;个人比较推荐第一种&#xff1a; 1、新建一个导出数据的实体类&#xff0c;用ExcelProperty()注解标明excel中列的中文名称&#xff1b;如果实体的类某些列不想导出&#xff0c;可以使用ExcelIgnore进行忽略就可以了。 2、使用easyexc…