文章插图
事务执行直接调用TransactionalTemplate的execute()方法
io.seata.tm.api.TransactionalTemplate#execute()
文章插图
io.seata.tm.api.GlobalTransactionContext#getCurrent() 获取当前事务
文章插图
io.seata.tm.api.TransactionalTemplate#beginTransaction()
文章插图
tx是DefaultGlobalTransaction
io.seata.tm.api.DefaultGlobalTransaction#begin()
DefaultGlobalTransaction中的TransactionManager是DefaultTransactionManager
文章插图
DefaultTransactionManager中提供了事务相关的底层操作
文章插图
io.seata.tm.api.DefaultGlobalTransaction#commit()
文章插图
io.seata.tm.api.DefaultGlobalTransaction#rollback()的逻辑与commit()类似,都是重试调用transactionManager.rollback(xid)
全局事务扫描器部分的代码就看到这里,下面总结一下:
1、配置项seata.enabled=true 会触发 SeataAutoConfiguration 自动配置
2、SeataAutoConfiguration中创建了一个GlobalTransactionScanner
3、GlobalTransactionScanner继承了AbstractAutoProxyCreator,并实现InitializingBean接口
4、初始化TM、RM
5、由于继承了AbstractAutoProxyCreator,所以BeanFactory会调用GlobalTransactionScanner#方法postProcessAfterInitialization(),最终会调用GlobalTransactionScanner#wrapIfNecessary()来为目标对象创建代理对象
6、GlobalTransactionScanner#wrapIfNecessary()中创建了一个GlobalTransactionalInterceptor,GlobalTransactionalInterceptor是一个MethodInterceptor
7、在创建代理对象的时候,在AbstractAutoProxyCreator#wrapIfNecessary()方法中,为代理对象应用GlobalTransactionalInterceptor,于是所有目标对象上的方法调用就会转为调用GlobalTransactionalInterceptor#invoke()
8、GlobalTransactionalInterceptor#invoke()方法中,首先获取被调用的目标对象的Class和Method对象,然后检查目标方法或类上是否有@GlobalTransactional或@GlobalLock注解,而且配置项中不能禁用全局事务
9、如果加了@GlobalTransactional注解,则创建一个AspectTransactional,然后开始处理全局事务,默认传播特性是REQUIRED
10、如果加了@GlobalLock注解,则开始处理全局锁
11、处理全局事务就是直接调用事务模板中的execute方法,TransactionalTemplate#execute()是一个模板方法,其中定义了事务处理的流程 。首先开启事务,然后执行业务逻辑,最后提交事务,异常回滚事务 。
12、事务操作是在DefaultGlobalTransaction中处理的,最终处理在DefaultTransactionManager 。DefaultTransactionManager负责同步远程调用,向TC发请求来开启、提交、回滚事务等操作
文章插图
3. 数据库操作执行SQL语句
通过Java自带的JDBC操作数据库通常是这样的:
Class.forName(driverClass);// 获取ConnectionConnection connection = DriverManager.getConnection(url,user,password);// 创建Statement或者PreparedStatementStatement stmt = connection.createStatement();stmt.execute(sql);// PreparedStatement ps = connection.prepareStatement(sql);// ps.execute();
MyBatis底层也是这一套接下来看Seata是如何做的
首先是获取数据库连接Connection,前面已经说过了,调用DataSource的getConnection()方法底层是在代理对象SeataDataSourceProxy上调用getConnection() 。SeataDataSourceProxy是接口,如果是AT模式,则这个数据源代理对象是DataSourceProxy
经验总结扩展阅读
- .NET 源码学习 [数据结构-线性表1.2] 链表与 LinkedList<T>
- Redisson源码解读-公平锁
- OpenHarmony移植案例: build lite源码分析之hb命令__entry__.py
- 【深入浅出 Yarn 架构与实现】1-2 搭建 Hadoop 源码阅读环境
- Redisson源码解读-分布式锁
- 源码级深度理解 Java SPI
- Dubbo-聊聊通信模块设计
- 【lwip】10-ICMP协议&源码分析
- 【lwip】09-IPv4协议&超全源码实现分析
- 从BeanFactory源码看Bean的生命周期