0
点赞
收藏
分享

微信扫一扫

Spring Tx (九) (Spring 事务源码分析)


文章目录

  • ​​1.Spring 事务工作流程​​
  • ​​2.Spring 事务源码分析​​
  • ​​2.1 创建代理对象​​
  • ​​3.Spring 事务执行分析​​
  • ​​3.1 事务执行源码分析​​

1.Spring 事务工作流程

Spring Tx (九) (Spring 事务源码分析)_java

  1. 获取到切面方法, 和所有切面匹配, 事务属性放入缓存attributeCache
  2. 创建Aop代理对象, 选择Jdk 和 Cglib

Spring Tx (九) (Spring 事务源码分析)_spring_02


事务处理:

  1. 缓存拿到事务属性
  2. 创建并开启事务
  3. 执行业务逻辑
  4. 提交或者回滚事务

2.Spring 事务源码分析

refresh()

Spring Tx (九) (Spring 事务源码分析)_前端_03

finishBeanFactoryInitialization()

Spring Tx (九) (Spring 事务源码分析)_前端_04

preInstantiateSingletons()

Spring Tx (九) (Spring 事务源码分析)_java_05

Spring Tx (九) (Spring 事务源码分析)_spring_06

doGetBean()

Spring Tx (九) (Spring 事务源码分析)_java_07

doCreateBean()

Spring Tx (九) (Spring 事务源码分析)_前端_08

initializeBean()

Spring Tx (九) (Spring 事务源码分析)_数据库连接_09

Spring Tx (九) (Spring 事务源码分析)_java_10

applyBeanPostProcessorsAfterInitialization()

Spring Tx (九) (Spring 事务源码分析)_spring_11

2.1 创建代理对象

Spring Tx (九) (Spring 事务源码分析)_数据库连接_12

Spring Tx (九) (Spring 事务源码分析)_spring_13

获取切面列表

Spring Tx (九) (Spring 事务源码分析)_前端_14

findCandidateAdvisors()

Spring Tx (九) (Spring 事务源码分析)_缓存_15

Spring Tx (九) (Spring 事务源码分析)_数据库连接_16

Spring Tx (九) (Spring 事务源码分析)_缓存_17

Spring Tx (九) (Spring 事务源码分析)_spring_18

findEligibleAdvisors(): 开始匹配对应的切面

Spring Tx (九) (Spring 事务源码分析)_前端_19

Spring Tx (九) (Spring 事务源码分析)_java_20

Spring Tx (九) (Spring 事务源码分析)_java_21

Spring Tx (九) (Spring 事务源码分析)_java_22

canApply(): 匹配对应的切面

Spring Tx (九) (Spring 事务源码分析)_缓存_23

Spring Tx (九) (Spring 事务源码分析)_前端_24

如果匹配了, 会将事务的属性加入到attributeCache缓存中

getTransactionAttribute()

Spring Tx (九) (Spring 事务源码分析)_spring_25

Spring Tx (九) (Spring 事务源码分析)_缓存_26

Spring Tx (九) (Spring 事务源码分析)_数据库连接_27

Spring Tx (九) (Spring 事务源码分析)_前端_28

从 element 对象中获取到@Transactional 注解

Spring Tx (九) (Spring 事务源码分析)_前端_29

Spring Tx (九) (Spring 事务源码分析)_数据库连接_30

getTransactionAttribute()

Spring Tx (九) (Spring 事务源码分析)_前端_31

创建Aop对象

Spring Tx (九) (Spring 事务源码分析)_spring_32

3.Spring 事务执行分析

Spring Tx (九) (Spring 事务源码分析)_数据库连接_33

Cglib 代理对象进行

Spring Tx (九) (Spring 事务源码分析)_缓存_34

Spring Tx (九) (Spring 事务源码分析)_spring_35

Spring Tx (九) (Spring 事务源码分析)_缓存_36


Spring Tx (九) (Spring 事务源码分析)_前端_37

3.1 事务执行源码分析

Spring Tx (九) (Spring 事务源码分析)_spring_38

  1. 从缓存中获取事务相关属性
  2. 创建事务: 获取事务, 设置事务属性, 开启事务
  3. 执行业务逻辑
  4. 回滚事务: 判断异常类型判断是否回滚, 执行回滚

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {

//获取我们的事务属源对象
TransactionAttributeSource tas = getTransactionAttributeSource();
//通过事务属性源对象获取到我们的事务属性信息
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
//获取我们配置的事务管理器对象
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
//从tx属性对象中获取出标注了@Transactionl的方法描述符
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

//处理声明式事务
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
//有没有必要创建事务
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);

Object retVal;
try {
//调用钩子函数进行回调目标方法
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
//抛出异常进行回滚处理
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
//清空我们的线程变量中transactionInfo的值
cleanupTransactionInfo(txInfo);
}
//提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
//编程式事务
else {
// 这里不是我们的重点,省略...
}
}

invokeWithinTransaction() 中获取事务的入口

Spring Tx (九) (Spring 事务源码分析)_spring_39

从 attributeCache 获取事务的缓存数据

Spring Tx (九) (Spring 事务源码分析)_缓存_40

创建事务

Spring Tx (九) (Spring 事务源码分析)_前端_41

Spring Tx (九) (Spring 事务源码分析)_前端_42

获取事务状态

Spring Tx (九) (Spring 事务源码分析)_java_43

doGetTransaction(): 获取事务

Spring Tx (九) (Spring 事务源码分析)_缓存_44

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");
}
//把我们的数据库连接包装成一个ConnectionHolder对象 然后设置到我们的txObject对象中去
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}

//标记当前的连接是一个同步事务
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();

//为当前的事务设置隔离级别
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");
}
con.setAutoCommit(false);
}

//判断事务为只读事务
prepareTransactionalConnection(con, definition);
//设置事务激活
txObject.getConnectionHolder().setTransactionActive(true);

//设置事务超时时间
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}

// 绑定我们的数据源和连接到我们的同步管理器上 把数据源作为key,数据库连接作为value 设置到线程变量中
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);
}
}

invokeWithinTransaction() 获取到txInfo 对象

Spring Tx (九) (Spring 事务源码分析)_缓存_45

执行逻辑

Spring Tx (九) (Spring 事务源码分析)_java_46

Spring Tx (九) (Spring 事务源码分析)_java_47

Spring Tx (九) (Spring 事务源码分析)_前端_48

Spring Tx (九) (Spring 事务源码分析)_前端_49

Spring Tx (九) (Spring 事务源码分析)_前端_50

Spring Tx (九) (Spring 事务源码分析)_spring_51

回滚事务

Spring Tx (九) (Spring 事务源码分析)_缓存_52

Spring Tx (九) (Spring 事务源码分析)_缓存_53

Spring Tx (九) (Spring 事务源码分析)_数据库连接_54

Spring Tx (九) (Spring 事务源码分析)_缓存_55

Spring Tx (九) (Spring 事务源码分析)_数据库连接_56

如果抛出的异常类型,和事务定义的异常类型匹配,证明该异常需要捕获。

之所以用递归,不仅需要判断抛出异常的本身,还需要判断它继承的父类异常,满足任意一个即可捕获。

Spring Tx (九) (Spring 事务源码分析)_前端_57


举报

相关推荐

0 条评论