Spring @Transaction 注解执行事务的流程
作者:程序员小航 发布时间:2022-12-30 15:41:23
前言
相信小伙伴一定用过 @Transaction 注解,那 @Transaction 背后的秘密又知道多少呢?
Spring 是如何开启事务的?又是如何进行提交事务和关闭事务的呢?
画图猜测
在开始 debug 阅读源码之前,小伙伴们应该已经知道 MySQL 是如何开启事务的。
因此可以得出猜测:
那下面跟着源码一起读一读,Spring 的 @Transaction 注解是如何执行事务逻辑的?
Spring 事务执行流程
开启事务
这里使用的是 Spring Boot + MySQL + Druid
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</dependency>
在创建 Bean 的时候,会对 UserService
基于 AOP 生成代理对象;
AbstractAutowireCapableBeanFactory#initializeBean
...
wrapIfNecessary
AbstractAutoProxyCreator#createProxy
CglibAopProxy#getProxy 生成代理对象
开始执行
userService.updateUserInfo();
这里的 userService 就是代理对象;会被CglibAopProxy.DynamicAdvisedInterceptor#intercept
方法拦截;TransactionInterceptor#invoke
被事务 * 拦截TransactionAspectSupport#invokeWithinTransaction
事务处理AbstractPlatformTransactionManager#getTransaction
会在这里调用AbstractPlatformTransactionManager#startTransaction
方法,来开启事务。
是不是看到 doBegin 这个词突然感觉很熟悉。
跟进 DataSourceTransactionManager#doBegin
方法,注意看,此时是在 spring-jdbc-5.3.8.jar
包下面的。
因为使用的 druid 连接池,所以这块 Connection
是 durid 的连接池。
DruidPooledConnection#setAutoCommit(false)
关闭自动提交;
这里就是 druid 的逻辑,一顿执行然后到 com.alibaba.druid.filter.FilterChainImpl#connection_setAutoCommit
。
ConnectionImpl#setAutoCommit
,这个是在 mysql-connector-java-8.0.25.jar
包下的。
这一句才是重点 SET autocommit=0
。
SET autocommit=0
开启事务了!
总结一下流程:
执行 SQL
在开始事务之后,会通过回调执行方法的内部逻辑。
因为这里使用的是 Mybatis,所以还是会被代理,
MapperProxy#invoke
;DruidPooledPreparedStatement#execute
;ClientPreparedStatement#execute
;
执行过程相对比较简单:
提交事务
在 TransactionAspectSupport#invokeWithinTransaction
最后一行,commitTransactionAfterReturning(txInfo);
就是提交事务。
AbstractPlatformTransactionManager#commit
抽象事务管理器,进行提交事务DataSourceTransactionManager#doCommit
数据源数据管理器,提交事务
这里肯定是调用连接池的方法,所以会执行到 DruidPooledConnection
中
DruidPooledConnection commit
最终还是执行到
mysql-connector-java-8.0.25.jar
包下面的ConnectionImpl#commit
调用 commit
提交事务。
commit
异常回滚
异常在这里 TransactionAspectSupport#invokeWithinTransaction
会被 catch。
AbstractPlatformTransactionManager#rollback
在这里进行 rollback
执行 DataSourceTransactionManager#doRollback
最终执行到 mysql-connector-java-8.0.25.jar
的 ConnectionImpl#rollback()
到 ConnectionImpl#rollbackNoChecks
从而执行 rollback 语句
rollback
恢复 autocommit
cleanupTransactionInfo(txInfo);
在 这个方法中会将之前设置的 autocommit 进行恢复。
Java 原生开启事务
如果觉得这样有点绕,那咱们可以看简单版本的,不带 Spring。
/**
* @author liuzhihang
* @date 2021/6/18 16:51
*/
public class MainTest {
public static void main(String[] args) throws Exception {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/demo");
dataSource.setUsername("root");
dataSource.setPassword("root");
Connection connection = dataSource.getConnection();
try {
// 关闭自动提交
connection.setAutoCommit(false);
connection.prepareStatement("update user_info set user_name = 'liuzhihang' where user_id = '1001';").executeUpdate();
connection.prepareStatement("update user_address set address = 'anhui' where user_id = '1001';").executeUpdate();
// 提交事务
connection.commit();
} catch (Exception e) {
// 回滚
connection.rollback();
} finally {
// 开启自动提交
connection.setAutoCommit(true);
}
}
}
看完 Java 原生提交事务的方式,是不是感觉简单明了。
Spring @Transaction 只是创建了 AOP 代理,通过代理调用原生的开启关闭事务,同样在执行 SQL 那一块,也是 Mybatis 进行了代理,从而提交 SQL。
来源:https://www.cnblogs.com/liuzhihang/p/14929912.html


猜你喜欢
- 1、JDBCJDBC 就是 数据库开发 操作的 代名词,因为只要是现代商业项目的开发那么一定是离不开 数据库 的,不管你搞的是什么,只要是想
- 1. 你可以讲下进程与线程的区别?为什么要用多线程?进程:进程是程序的一次执行过程,是系统运行程序的基本单位。线程:单个进程中执行中每个任务
- 引言:编写高效简洁的C语言代码,是许多软件工程师追求的目标。本文就工作中的一些体会和经验做相关的阐述,不对的地方请各位指教。第1招:以空间换
- 程序中的错误分为编译时的错误和运行时的错误。编译时的错误主要是语法错误,比如:句尾没有加分号,括号不匹配,关键字错误等,这类错误比较容易修改
- Android 消息分发使用EventBus的实例详解1. AndroidStudio使用dependencies {//最新版本 &nbs
- 一、项目运行环境配置:Jdk1.8 + Tomcat8.5 + Mysql + HBuilderX(Webstorm也行)+ Eclispe
- 介绍MVC(Model-View-Controller)是一种软件架构模式,其中应用程序被划分为三个部分:模型(Model)、视图(View
- 高斯模糊是什么?高斯模糊(英语:Gaussian Blur),也叫高斯平滑,是在Adobe Photoshop、GIMP以及Paint.NE
- 前言前面几篇我们简单的复习了一下自定义 View 的测量与绘制,并且回顾了常见的一些事件的处理方式。那么如果我们想自定义 ViewGroup
- 通常同步意味着一个任务的某个处理过程会对多个线程在用串行化处理,而
- Maven 错误找不到符号问题,通常有三种原因: 1. 可能项目编码格式不统一。 2. 可能项目编码使用的JDK版本不统一。 3
- Android 媒体库数据更新方法总结在项目中,我们经常要创建个自己的目录,里面存放一些图片啊文件之类,比如:我在SD卡中刚创建了一个文件夹
- C#删除只读文件的方法: if (File.GetAttributes(FFName).ToString().IndexOf("R
- 本文介绍IntelliJ IDEA中Project 窗口的一些设置技巧,参考IntelliJ IDEA 简体中文专题教程,英文好的同学可以查
- 网上找了几个,写的都不太适合,有的写出来了,也没有给出参考的算法链接。这样就导致了如果产生错误我们无法排查(不懂原理怎么排查对吧)。如果在使
- 背景前些天遇到一个需求,在没有第三方源码的情况下,刷新一个第三方UI,并且拦截到其ajax请求的返回结果。当结果为AVALIABLE的时候,
- Android activity和view判断滑动 实例代码://手
- 1.c#里面的TabControl控件没有关闭按钮,而且很难看。2.有一些已经做好的第三方控件,但是收费。3.由于我的故障树推理诊断项目在绘
- 前言由于现在网络层已经升级到RxJava2.x相关的了,所以需要做些调整。虽然RxJava1.x和RxJava2.x同属RxJava系列,但
- 只需要下载相应的zip包,不需装什么手机助手。1、下载相应zip包(ROM)http://download.mokeedev.com/比如我