Spring源码-事务控制与底层源码

我在之前的3篇文章里已经把AOP的底层以及重点说清楚了,这里我们就来说一下也是基于AOP来实现的Spring事物的问题,尽量一篇文章让你看懂它的来世今生.

1. Spring事物控制基础

首先,我们在MySQL里也接触过事务的概念,那事务是什么呢?简单点说就是一件事要不全部做完成功 ,要不然全部失败 ,那当然事务也是有ACID这四个特征。原子性、一致性、隔离性、持久性

Spring提供了声明式事务管理,通过AOP和代理模式来实现事务控制。Spring会为配置了事务的Bean创建一个代理对象,在方法调用前后插入事务逻辑。这里一般有2种配置,XML配置和注解配置。

2. Spring事物的一些高级特性

2.1 事物传播行为

我们首先要知道什么是事务传播,简单来说当一个事务在调用另一个事务的时候,如何处理事务的问题。

Spring定义了7种传播行为:

  • REQUIRED:默认,当前存在事务则加入,否则新建。
  • REQUIRES_NEW:始终新建事务,挂起当前事务(若有)。
  • NESTED:在嵌套事务中执行(基于保存点)。
  • SUPPORTS:存在事务则加入,否则非事务执行。
  • NOT_SUPPORTED:非事务执行,挂起当前事务(若有)。
  • MANDATORY:必须存在事务,否则抛出异常。
  • NEVER:必须非事务执行,否则抛出异常。

事物传播的源码在AbstractPlatformTransactionManager#handleExistingTransaction里,我这里贴一种就行,整体的逻辑一样:

scss 复制代码
// 处理 PROPAGATION_NOT_SUPPORTED
    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
        // 挂起当前事务
        Object suspendedResources = suspend(transaction);
        boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
        return newTransactionStatus(null, false, newSynchronization, ...);
    }

2.2 事物的隔离级别与回滚规则

Spring支持数据库的四种隔离级别,读未提交、读已提交、不可重复读、串行执行。

而Spring的回滚规则有两种:

  • RuntimeExceptionError触发回滚
  • Checked Exception不触发回滚

可通过@TransactionalrollbackFornoRollbackFor属性自定义回滚策略

3. Spring事物的底层实现

Spring事务管理的核心是TransactionInterceptorTransactionAspectSupport

3.1 TransactionInterceptor

TransactionInterceptor,我们看名字就知道它是一个拦截器,负责拦截方法,在方法调用前后处理事务。核心方法是 invoke

java 复制代码
public Object invoke(MethodInvocation invocation) throws Throwable {
    Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
    Method method = invocation.getMethod();
    //执行事物逻辑
    return invokeWithinTransaction(method, targetClass, invocation::proceed);
}

这里invokeWithinTransaction是事务管理的关键方法,负责创建、提交、回滚事务。

3.2 TransactionAspectSupport

TransactionAspectSupport是事物执行的底层流程,在invokeWithinTrasaction方法中整个流程是: 解析注解或者XML->根据你定义的传播行为决定是否开启新事物->执行目标方法->捕获异常并根据定义的规则进行回滚->提交事物

scss 复制代码
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, InvocationCallback invocation) throws Throwable {
    // 获取事务属性
    TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
    // 获取事务管理器
    PlatformTransactionManager tm = determineTransactionManager(txAttr);
    // 创建事务
    TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, method.toString());
    Object retVal;
    try {
        // 执行目标方法
        retVal = invocation.proceedWithInvocation();
    } catch (Throwable ex) {
        // 异常时回滚
        completeTransactionAfterThrowing(txInfo, ex);
        throw ex;
    } finally {
        cleanupTransactionInfo(txInfo);
    }
    // 提交事务
    commitTransactionAfterReturning(txInfo);
    return retVal;
}

3.3 事物的创建、提交和回滚

这里分别的三个方法就是上面调用的三个方法:

  • 创建:createTransactionIfNecessary 根据事务属性和当前状态创建新事务或加入现有事务。
  • 提交:commitTransactionAfterReturning 在方法正常返回后提交事务。
  • 回滚:completeTransactionAfterThrowing 在异常时根据回滚规则决定是否回滚。

4. 示例

我们在使用的时候是这样的:

typescript 复制代码
@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    @Transactional
    public void createUser(String username) {
        userRepository.save(new User(username));
        if (username.equals("error")) {
            throw new RuntimeException("User creation failed");
        }
    }
}
  • 这里为UserService创建代理,拦截createUser方法来进行调用。
  • 上述的TransactionInterceptor根据@Transaction来创建事务。
  • 执行createUser这个事务,保存用户数据。
  • 然后如果username为error的话就会抛出异常,不然就直接提交事务。

5. 总结与一些问题

事务失效:在某些情况下,事务会失效,有一些典型场景。

  • 方法非public:@Transactional注解只用在public方法里
  • 自调用问题:同一类中方法A调用方法B,B的事务注解失效

另外还有一些分布式事务,或者与锁结合也是面试中会问到的。Spring 事务控制通过声明式管理,结合 AOP 和代理模式,简化了事务处理的复杂度。其核心实现依赖 TransactionInterceptor 和 TransactionAspectSupport,通过源码分析可以看出,Spring 在事务的创建、提交和回滚过程中提供了高度灵活性和可配置性。

相关推荐
芦屋花绘6 分钟前
Java的JUC详细全解
java·开发语言·jvm·spring boot·kafka
珠峰下的沙砾14 分钟前
如何将IDP映射属性添加,到accountToken中 方便项目获取登录人信息
java
lfwh20 分钟前
Java 实现单链表翻转(附详细注释)
java·开发语言·python
元亓亓亓1 小时前
java后端开发day35--集合进阶(四)--双列集合:Map&HashMap&TreeMap
java·开发语言
Lafar1 小时前
FlutterBoost 原理与优缺点分析
面试
江城开朗的豌豆1 小时前
JavaScript篇:JavaScript事件循环:从厨房看异步编程的奥秘
前端·javascript·面试
全栈老李技术面试1 小时前
【高频考点精讲】JavaScript中的访问者模式:从AST解析到数据转换的艺术
开发语言·前端·javascript·面试·html·访问者模式
独立开阀者_FwtCoder2 小时前
狂收 33k+ star!全网精选的 MCP 一网打尽!!
java·前端·javascript
再路上12162 小时前
direct_visual_lidar_calibration iridescence库问题
java·服务器·数据库
兔子蟹子2 小时前
Java 实现SpringContextUtils工具类,手动获取Bean
java·开发语言