spring复习:(43)使用TransactionProxyFactoryBean来实现事务时,事务是怎么开启的?

news2024/11/29 23:46:33

一、配置文件:

    <bean id="myFactoryBean"
          class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager" ref="transactionManager" />
        <property name="target" ref="studentService" />
        <property name="transactionAttributes">
            <props>
                <prop key="*">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
    </bean>

二、代码块中使用TransactionProxyFactoryBean

package cn.edu.tju.study.service.transaction2;

public interface StudentService {
    public void addStudent(String name, int age);
}

package cn.edu.tju.study.service.transaction2;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

@Service
public class StudentServiceImpl implements StudentService{
    private JdbcTemplate jdbcTemplate;

    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @Override
    public void addStudent(String name,int age) {
        String sql = "insert into student values('";
        sql += name;
        sql +="'";
        sql += ",";
        sql += age;
        sql += ")";
        jdbcTemplate.execute(sql);
        jdbcTemplate.execute(sql);

    }
}

package cn.edu.tju.study.service.transaction2;

import cn.edu.tju.study.service.MyConfig3;
import cn.edu.tju.study.service.aspect.MyDemoService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TransactionTest {
    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("transaction.xml");

        StudentService studentService = context.getBean("myFactoryBean", StudentService.class);

        studentService.addStudent("paul",23);
    }
}

三、执行流程
当调用addStudent时,会直接跳转到JdkDynamicAopProxy的invoke方法(因为实现了接口,代理对象的实现为jdk 动态代理)
在这里插入图片描述
执行到invoke方法的
List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);时,chain中包含一个对象:TransactionInterceptor.
执行到retVal = invocation.proceed();会进到ReflectiveMethodInvocation类:
在这里插入图片描述
该方法执行到return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);时,会进到TransactionInterceptor类:
在这里插入图片描述
其中调用的invokeWithinTransaction代码如下:

	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 TransactionManager tm = determineTransactionManager(txAttr);

		if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
			ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
				if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
					throw new TransactionUsageException(
							"Unsupported annotated transaction on suspending function detected: " + method +
							". Use TransactionalOperator.transactional extensions instead.");
				}
				ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType());
				if (adapter == null) {
					throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +
							method.getReturnType());
				}
				return new ReactiveTransactionSupport(adapter);
			});
			return txSupport.invokeWithinTransaction(
					method, targetClass, invocation, txAttr, (ReactiveTransactionManager) tm);
		}

		PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

		if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
			// Standard transaction demarcation with getTransaction and commit/rollback calls.
			TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

			Object retVal;
			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);
			}

			if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {
				// Set rollback-only in case of Vavr failure matching our rollback rules...
				TransactionStatus status = txInfo.getTransactionStatus();
				if (status != null && txAttr != null) {
					retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
				}
			}

			commitTransactionAfterReturning(txInfo);
			return retVal;
		}

		else {
			final ThrowableHolder throwableHolder = new ThrowableHolder();

			// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
			try {
				Object result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {
					TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
					try {
						Object retVal = invocation.proceedWithInvocation();
						if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {
							// Set rollback-only in case of Vavr failure matching our rollback rules...
							retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
						}
						return retVal;
					}
					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;
			}
		}
	}

其中调用了createTransactionIfNecessary
在这里插入图片描述
它的代码如下:
在这里插入图片描述
其中调用了getTransaction,它的代码如下:

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

其中调用的startTransaction代码如下:
在这里插入图片描述
其中调用的doBegin代码如下:

	protected void doBegin(Object transaction, TransactionDefinition definition) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		Connection con = null;

		try {
			if (!txObject.hasConnectionHolder() ||
					txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
				Connection newCon = obtainDataSource().getConnection();
				if (logger.isDebugEnabled()) {
					logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
				}
				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);
		}
	}

可以看到其中设置手动提交事务的代码
在这里插入图片描述

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

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

相关文章

可以替代微软 Exchange 的 几个开源软件分享给你

微软Exchange是一个功能强大的邮件和群件解决方案&#xff0c;但对于一些用户来说&#xff0c;寻找替代方案可能是必要的。幸运的是&#xff0c;有几个开源软件提供了可靠而且功能丰富的替代选项。这些开源软件不仅可以满足组织和个人的邮件和协作需求&#xff0c;还具有灵活性…

quartus18.0如何下载安装Cyclone V器件库

文章目录 前言一、下载流程二、添加步骤三、总结四、参考资料 前言 在我们使用不同版本的板子的时候&#xff0c;我们需要在quartus下安装不同型号的器件库才能对板子进行选型并进行下一步操作。 一、下载流程 官网下载地址 这里我们点击支持选中下载中心&#xff1a; 选择FPGA…

reggie优化04-Nginx

官方网站下载&#xff1a;http://nginx.org/en/download.html 1、Nginx安装 这里需要在Linux系统下&#xff1a; 安装wget工具&#xff1a;yum install wget&#xff08;或者官网下载直接上传到Linux&#xff09; 安装树形结构tree&#xff1a;yum install tree 2、Nginx命令 …

在云计算环境中,保护Java应用程序可用的有效措施和工具

云计算&#xff08;Cloud&#xff09;技术是近年来计算机科学的一个重要突破。大多数组织已经通过将自己的应用程序移入云平台而获益。不过&#xff0c;如何保证应用程序在第三方服务器上的安全性&#xff0c;是一项艰巨的挑战。 在本文中&#xff0c;我们将重点讨论Java&…

Notepad++ 配置python虚拟环境(Anaconda)

Notepad配置python运行环境步骤&#xff1a; 打开Notepad ->”运行”菜单->”运行”按钮在弹出的窗口内输入以下命令&#xff1a; 我的conda中存在虚拟环境 (1) base (2) pytorch_gpu 添加base环境至Notepad中 cmd /k chdir /d $(CURRENT_DIRECTORY) & call cond…

《零基础入门学习Python》第036讲:类和对象:给大家介绍对象

0. 请写下这一节课你学习到的内容&#xff1a;格式不限&#xff0c;回忆并复述是加强记忆的好方式&#xff01; &#xff08;一&#xff09;对象 这节课给大家介绍对象。我们之前说过Python无处不对象&#xff0c;Python到处都是对象&#xff0c;然而我们很多人不理解对象到底…

NB!更方便Xshell本地密码破解工具

工具介绍 XshellCrack是基于SharpXDecrypt的二次开发&#xff0c;用go语言重写&#xff0c;增加了注册表查询设置&#xff0c;更方便xshell本地密码破解。 关注【Hack分享吧】公众号&#xff0c;回复关键字【230717】获取下载链接 工具使用 Usage:root SshCrack [flags]Flags…

在线看板工具Restyaboard

本文软件由网友 yf33 推荐&#xff1b; 什么 Restyaboard &#xff1f; Restyaboard 是一款类 Trello 应用&#xff0c;支持看板、任务、待办事项、聊天等。Restyaboard 的面板能为您提供项目当前状态的视觉概览&#xff0c;并通过让您专注于最重要的几个项目来提高您的工作效率…

FiddlerScript修改指定参数的返回值

FiddlerScript修改指定参数的返回值 使用场景&#xff1a; api/Live/GetLiveList接口&#xff1a; &#xff08;1&#xff09;Type为1&#xff0c;接口返回直播列表 &#xff08;2&#xff09;Type为2&#xff0c;接口返回回放列表 现在想修改直播列表的返回值 思路&#…

【Redis】6、Redisson 分布式锁的简单使用(可重入、重试机制...)

目录 零、自己通过 set nx ex 实现的分布式锁存在的问题一、Redisson 介绍二、Redisson 基本使用&#xff08;改造业务&#xff09;(1) 依赖(2) 配置 Redisson 客户端(3) 使用 Redisson 的可重入锁 三、Redisson 可重入锁原理四、Redisson 可重试原理五、Redisson 超时释放&…

线数据的按节点打断

思想&#xff1a;运行要素转线工具箱 原始数据 运行完数据 数量由7变成27

Springboot + Vue 下载Word、PDF文档并保留内部格式

相对于上传&#xff0c;下载时复杂的地方就是文件中文名称乱码 前端 <el-button click"clickCall(handleExport, scope,index)">导出</el-button>// 文件下载操作handleExport(row) {axios.get(**********master/proj/exportContract?id" row.id,…

前端node.js入门

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 Node.js 入门 什么是 Node.js&#xff1f; 什么是前端工程化&#xff1f; Node.js 为何能执行 JS&…

netty组件详解-上

netty服务端示例: private void doStart() throws InterruptedException {System.out.println("netty服务已启动");// 线程组EventLoopGroup group new NioEventLoopGroup();try {// 创建服务器端引导类ServerBootstrap server new ServerBootstrap();// 初始化服…

CDHD高创驱动器通过ServoStudio备份和恢复参数的具体方法步骤

CDHD高创驱动器通过ServoStudio备份和恢复参数的具体方法步骤 硬件连接: 如下图所示,通过通信线缆将伺服驱动器和电脑进行连接,一端为RJ11,一端为USB, 软件连接: 打开伺服调试软件ServoStudio,在驱动器配置中找到连接—自动连接,点击搜索&连接,此时软件会自动搜索…

基于jsp+sevlet+mysql实验室设备管理系统2.0

基于jspsevletmysql实验室设备管理系统2.0 一、系统介绍二、功能展示1.控制台2.申购设备3.设备列表4.设备维护5.设备类型6.报废设备7.维修记录 四、其他系统实现五、获取源码 一、系统介绍 系统主要功能&#xff1a; 普通用户&#xff1a;控制台、申购设备、设备列表、设备维护…

docker 安装oracle 11g

docker 安装oracle 11g 拉取镜像 docker pull registry.cn-hangzhou.aliyuncs.com/helowin/oracle_11g创建容器 docker run -d -p 1521:1521 --name oracle11g registry.cn-hangzhou.aliyuncs.com/helowin/oracle_11gD:\docker\oracle\oracle11g>docker exec -it oracle11…

CMU 15-445 -- Query Optimization - 10

CMU 15-445 -- Query Optimization - 10 引言Query Optimization TechniquesQuery RewritingPredicate PushdownProjections Pushdown Cost-based SearchCost EstimationStatisticsEquality PredicateRange PredicateNegation QueryConjunction QueryDisjunction QueryJoins直方…

山西电力市场日前价格预测【2023-07-19】

日前价格预测 预测明日&#xff08;2023-07-19&#xff09;山西电力市场全天平均日前电价为362.73元/MWh。其中&#xff0c;最高日前电价为395.74元/MWh&#xff0c;预计出现在06: 00。最低日前电价为316.17元/MWh&#xff0c;预计出现在13: 45。 价差方向预测 1&#xff1a;实…

ES6标准下在if中进行函数声明

ES5中规定&#xff0c;函数只能在顶层作用域或函数作用域之中声明&#xff0c;不能在块级作用域声明。 // 情况一 if (true) {function f() {} }// 情况二 try {function f() {} } catch(e) {// ... }上面两种函数声明&#xff0c;根据 ES5 的规定都是非法的。但是&#xff0c…