Spring AOP场景4——事务管理(源码分析)

在白嫖之前,希望你会内疚,最起码点个赞收藏再自取吧,源码在最后,自取;

在白嫖之前,希望你会内疚,最起码点个赞收藏再自取吧,源码在最后,自取;

在白嫖之前,希望你会内疚,最起码点个赞收藏再自取吧,源码在最后,自取;

本文从底层原理+核心代码 角度,拆解AOP实现事务控制的完整逻辑,重点分析Spring事务管理器(PlatformTransactionManager)的核心实现,以及AOP如何通过环绕通知织入事务逻辑。所有代码均为可理解的核心简化版,保留Spring原生逻辑但剔除冗余,便于学习核心思路。

一、核心前置知识

1. 事务的本质(数据库层面)

事务的底层是数据库连接(java.sql.Connection)的特性:

  • 默认autoCommit=true:执行每条SQL后自动提交;
  • 开启事务:connection.setAutoCommit(false)
  • 提交:connection.commit()
  • 回滚:connection.rollback()

Spring事务的本质是通过AOP拦截方法,统一管理数据库连接的事务状态,让业务代码无需感知连接操作。

2. AOP实现事务的核心角色

角色 作用
事务管理器(PlatformTransactionManager 封装事务的开启/提交/回滚逻辑(对接数据库连接)
事务拦截器(TransactionInterceptor AOP环绕通知的核心实现,触发事务管理器操作
动态代理(JDK/CGLIB) 为业务类生成代理对象,接管方法调用
事务注解(@Transactional 标记需要事务增强的方法,定义事务属性(传播行为、隔离级别等)

二、手写简化版AOP事务框架(理解底层)

先通过手写核心代码模拟Spring事务的实现逻辑,掌握AOP+事务的核心思路。

步骤1:定义事务注解(模拟@Transactional

java 复制代码
import java.lang.annotation.*;

/**
 * 自定义事务注解,标记需要事务控制的方法
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyTransactional {
    // 模拟事务传播行为(简化版)
    Propagation propagation() default Propagation.REQUIRED;

    // 事务隔离级别(简化版)
    Isolation isolation() default Isolation.DEFAULT;

    // 异常回滚规则
    Class<? extends Throwable>[] rollbackFor() default {Exception.class};
}

// 传播行为枚举(简化)
enum Propagation {
    REQUIRED // 默认:有事务则加入,无则新建
}

// 隔离级别枚举(简化)
enum Isolation {
    DEFAULT // 使用数据库默认隔离级别
}

步骤2:实现事务管理器(模拟DataSourceTransactionManager

java 复制代码
import org.springframework.jdbc.datasource.DataSourceUtils;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * 自定义事务管理器:封装数据库连接的事务操作
 * 核心:绑定连接到当前线程(ThreadLocal),保证同线程内方法共用一个连接
 */
public class MyTransactionManager {
    // 数据源(Spring中通过配置注入)
    private final DataSource dataSource;
    // 线程本地变量:存储当前线程的事务连接+状态
    private final ThreadLocal<TransactionInfo> threadLocal = new ThreadLocal<>();

    public MyTransactionManager(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    /**
     * 开启事务
     */
    public TransactionInfo begin(MyTransactional annotation) {
        // 1. 获取数据库连接(Spring中通过DataSourceUtils保证线程绑定)
        Connection conn = DataSourceUtils.getConnection(dataSource);
        TransactionInfo txInfo = new TransactionInfo();
        txInfo.setConn(conn);
        txInfo.setAnnotation(annotation);
        txInfo.setOldAutoCommit(true); // 保存原有autoCommit状态

        try {
            // 2. 关闭自动提交,开启事务
            if (conn.getAutoCommit()) {
                conn.setAutoCommit(false);
                txInfo.setOldAutoCommit(true);
            }
            // 3. 设置隔离级别(简化版)
            if (annotation.isolation() != Isolation.DEFAULT) {
                conn.setTransactionIsolation(annotation.isolation().ordinal() + 1);
            }
            // 4. 将事务信息绑定到当前线程
            threadLocal.set(txInfo);
            return txInfo;
        } catch (SQLException e) {
            throw new RuntimeException("开启事务失败", e);
        }
    }

    /**
     * 提交事务
     */
    public void commit(TransactionInfo txInfo) {
        if (txInfo == null) return;
        Connection conn = txInfo.getConn();
        try {
            if (conn != null && !conn.isClosed()) {
                conn.commit(); // 提交事务
                // 恢复原有autoCommit状态
                conn.setAutoCommit(txInfo.isOldAutoCommit());
            }
        } catch (SQLException e) {
            throw new RuntimeException("提交事务失败", e);
        } finally {
            // 释放连接+清空线程变量
            DataSourceUtils.releaseConnection(conn, dataSource);
            threadLocal.remove();
        }
    }

    /**
     * 回滚事务
     */
    public void rollback(TransactionInfo txInfo) {
        if (txInfo == null) return;
        Connection conn = txInfo.getConn();
        try {
            if (conn != null && !conn.isClosed()) {
                conn.rollback(); // 回滚事务
                conn.setAutoCommit(txInfo.isOldAutoCommit());
            }
        } catch (SQLException e) {
            throw new RuntimeException("回滚事务失败", e);
        } finally {
            DataSourceUtils.releaseConnection(conn, dataSource);
            threadLocal.remove();
        }
    }

    // 事务信息封装类
    public static class TransactionInfo {
        private Connection conn;
        private MyTransactional annotation;
        private boolean oldAutoCommit;

        // getter/setter 省略
    }
}

步骤3:实现AOP环绕通知(事务拦截器)

java 复制代码
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import java.lang.reflect.Method;

/**
 * 自定义事务拦截器:AOP环绕通知核心逻辑
 * 作用:拦截@MyTransactional注解的方法,织入事务开启/提交/回滚逻辑
 */
@Aspect
public class MyTransactionInterceptor {
    // 事务管理器(Spring中通过依赖注入)
    private final MyTransactionManager transactionManager;

    public MyTransactionInterceptor(MyTransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }

    /**
     * 环绕通知:拦截所有标注@MyTransactional的方法
     */
    @Around("@annotation(com.example.MyTransactional)")
    public Object intercept(ProceedingJoinPoint joinPoint) throws Throwable {
        // 1. 获取方法上的事务注解
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        MyTransactional annotation = method.getAnnotation(MyTransactional.class);

        MyTransactionManager.TransactionInfo txInfo = null;
        try {
            // 2. 开启事务
            txInfo = transactionManager.begin(annotation);
            // 3. 执行原始业务方法(核心:调用目标方法)
            Object result = joinPoint.proceed();
            // 4. 提交事务
            transactionManager.commit(txInfo);
            return result;
        } catch (Throwable e) {
            // 5. 异常回滚(判断是否符合回滚规则)
            if (isRollback(e, annotation.rollbackFor())) {
                transactionManager.rollback(txInfo);
            }
            throw e; // 抛出异常,上层可感知
        }
    }

    /**
     * 判断异常是否需要回滚
     */
    private boolean isRollback(Throwable e, Class<? extends Throwable>[] rollbackFor) {
        for (Class<? extends Throwable> clazz : rollbackFor) {
            if (clazz.isInstance(e)) {
                return true;
            }
        }
        return false;
    }
}

步骤4:配置类(开启AOP+注入组件)

java 复制代码
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.sql.DataSource;

/**
 * 配置类:组装AOP事务的核心组件
 */
@Configuration
@EnableAspectJAutoProxy // 开启AOP动态代理
public class TransactionConfig {
    // 1. 配置数据源
    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/test?useSSL=false");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        return dataSource;
    }

    // 2. 配置自定义事务管理器
    @Bean
    public MyTransactionManager myTransactionManager(DataSource dataSource) {
        return new MyTransactionManager(dataSource);
    }

    // 3. 配置事务拦截器(AOP切面)
    @Bean
    public MyTransactionInterceptor myTransactionInterceptor(MyTransactionManager transactionManager) {
        return new MyTransactionInterceptor(transactionManager);
    }
}

步骤5:业务层使用自定义事务注解

java 复制代码
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

@Service
public class OrderService {
    @Resource
    private DataSource dataSource;

    /**
     * 标记需要事务控制的业务方法
     */
    @MyTransactional(rollbackFor = {Exception.class})
    public void createOrder(Long productId, Integer num) throws SQLException {
        // 业务逻辑1:扣减库存
        deductStock(productId, num);
        // 业务逻辑2:创建订单(模拟异常:如果num>10则抛异常,触发回滚)
        if (num > 10) {
            throw new RuntimeException("库存超出限制");
        }
        createOrderRecord(productId, num);
    }

    // 扣减库存
    private void deductStock(Long productId, Integer num) throws SQLException {
        String sql = "UPDATE stock SET num = num - ? WHERE product_id = ?";
        try (Connection conn = dataSource.getConnection();
             PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setInt(1, num);
            ps.setLong(2, productId);
            ps.executeUpdate();
        }
    }

    // 创建订单记录
    private void createOrderRecord(Long productId, Integer num) throws SQLException {
        String sql = "INSERT INTO `order` (product_id, num) VALUES (?, ?)";
        try (Connection conn = dataSource.getConnection();
             PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setLong(1, productId);
            ps.setInt(2, num);
            ps.executeUpdate();
        }
    }
}

手写版核心逻辑总结

  1. 注解标记 :通过@MyTransactional标记需要事务的方法;
  2. AOP拦截:环绕通知拦截目标方法,触发事务逻辑;
  3. 事务管理器 :封装数据库连接的autoCommitcommitrollback操作;
  4. 线程绑定 :通过ThreadLocal保证同线程内的业务方法共用一个数据库连接(核心!否则多方法会用不同连接,事务失效)。

三、Spring原生事务管理器深度解析

Spring的PlatformTransactionManager是事务管理的核心接口,我们基于手写版对比,分析其原生实现。

1. 核心接口体系

java 复制代码
// Spring事务管理器顶级接口
public interface PlatformTransactionManager {
    // 获取事务(开启事务)
    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
    // 提交事务
    void commit(TransactionStatus status) throws TransactionException;
    // 回滚事务
    void rollback(TransactionStatus status) throws TransactionException;
}

// 事务定义(传播行为、隔离级别、超时时间等)
public interface TransactionDefinition {
    int PROPAGATION_REQUIRED = 0; // 默认传播行为
    int ISOLATION_DEFAULT = -1;    // 默认隔离级别
    // 省略其他常量+方法
}

// 事务状态(封装事务的连接、是否新建、是否回滚等)
public interface TransactionStatus extends SavepointManager {
    boolean isNewTransaction(); // 是否是新建事务
    boolean hasSavepoint();     // 是否有保存点
    void setRollbackOnly();     // 标记为回滚
    boolean isRollbackOnly();   // 是否需要回滚
    void flush();               // 刷新事务
    boolean isCompleted();      // 事务是否完成
}

2. 核心实现类:DataSourceTransactionManager

DataSourceTransactionManager是JDBC/MyBatis场景下的核心实现,核心方法拆解:

(1)开启事务:getTransaction()
java 复制代码
@Override
public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
    // 1. 获取事务定义(传播行为、隔离级别等)
    TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
    // 2. 获取数据源连接(绑定到当前线程)
    Object transaction = doGetTransaction();
    boolean debugEnabled = logger.isDebugEnabled();

    // 3. 处理传播行为(核心:判断是否新建事务/加入已有事务)
    if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED) {
        // 检查当前线程是否已有事务
        if (isExistingTransaction(transaction)) {
            // 有事务则加入(复用连接)
            return handleExistingTransaction(def, transaction, debugEnabled);
        }
        // 无事务则新建
        if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
            throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
        }
        // 4. 开启新事务(核心:获取连接+关闭autoCommit)
        return startNewTransaction(def, transaction, debugEnabled);
    }

    // 省略其他传播行为的处理...
}

// 核心:开启新事务
private TransactionStatus startNewTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
    // 5. 获取数据库连接(通过DataSourceUtils,保证线程绑定)
    Connection conn = DataSourceUtils.getConnection(obtainDataSource());
    txObject.setConnectionHolder(new ConnectionHolder(conn), true);
    // 6. 关闭自动提交,开启事务
    try {
        if (conn.getAutoCommit()) {
            txObject.setMustRestoreAutoCommit(true);
            if (debugEnabled) {
                logger.debug("Switching JDBC Connection [" + conn + "] to manual commit");
            }
            conn.setAutoCommit(false);
        }
        // 7. 设置隔离级别
        prepareTransactionalConnection(conn, definition);
        // 8. 标记事务为新建
        txObject.setNewTransaction(true);
        if (definition.isReadOnly()) {
            txObject.setReadOnly(true);
        }
        // 9. 返回事务状态
        return new DefaultTransactionStatus(
            txObject, true, false, definition.isReadOnly(), debugEnabled, null);
    } catch (SQLException ex) {
        DataSourceUtils.releaseConnection(conn, obtainDataSource());
        throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
    }
}
(2)提交事务:commit()
java 复制代码
@Override
public void commit(TransactionStatus status) throws TransactionException {
    DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
    // 1. 如果已标记回滚,则直接回滚
    if (defStatus.isRollbackOnly()) {
        processRollback(defStatus, false);
        return;
    }
    // 2. 非新建事务则不提交(交给外层事务处理)
    if (!defStatus.isNewTransaction()) {
        if (defStatus.hasTransaction()) {
            if (defStatus.isDebug()) {
                logger.debug("Not committing JDBC transaction because it's not a new transaction");
            }
        }
        return;
    }
    // 3. 新建事务则提交
    try {
        doCommit(defStatus);
    } catch (SQLException ex) {
        throw new TransactionSystemException("Could not commit JDBC transaction", ex);
    } finally {
        // 4. 释放连接+恢复autoCommit
        cleanupAfterCompletion(defStatus.getTransaction());
    }
}

// 实际提交逻辑
protected void doCommit(DefaultTransactionStatus status) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
    Connection con = txObject.getConnectionHolder().getConnection();
    if (status.isDebug()) {
        logger.debug("Committing JDBC transaction on Connection [" + con + "]");
    }
    try {
        con.commit(); // 数据库层面提交
    } catch (SQLException ex) {
        throw new TransactionSystemException("Could not commit JDBC transaction", ex);
    }
}
(3)回滚事务:rollback()
java 复制代码
@Override
public void rollback(TransactionStatus status) throws TransactionException {
    DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
    // 1. 非新建事务则标记回滚(交给外层处理)
    if (!defStatus.isNewTransaction()) {
        if (defStatus.hasTransaction()) {
            if (defStatus.isDebug()) {
                logger.debug("Setting JDBC transaction rollback-only");
            }
            defStatus.setRollbackOnly();
        }
        return;
    }
    // 2. 新建事务则直接回滚
    processRollback(defStatus, false);
}

// 实际回滚逻辑
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
    try {
        boolean rollback = true;
        // 处理保存点(简化版忽略)
        if (status.hasSavepoint()) {
            if (status.isDebug()) {
                logger.debug("Rolling back JDBC transaction to savepoint");
            }
            status.rollbackToSavepoint();
            rollback = false;
        }
        // 3. 回滚事务
        if (rollback) {
            doRollback(status);
        }
    } catch (SQLException ex) {
        throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
    } finally {
        // 4. 释放连接+恢复autoCommit
        cleanupAfterCompletion(status.getTransaction());
    }
}

protected void doRollback(DefaultTransactionStatus status) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
    Connection con = txObject.getConnectionHolder().getConnection();
    if (status.isDebug()) {
        logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
    }
    try {
        con.rollback(); // 数据库层面回滚
    } catch (SQLException ex) {
        throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
    }
}

3. Spring事务管理器核心设计思路

设计点 作用
接口抽象(PlatformTransactionManager 解耦事务逻辑与具体数据库类型(支持JDBC、JPA、Hibernate等)
线程绑定(TransactionSynchronizationManager 通过ThreadLocal存储当前线程的事务连接、事务状态,保证同线程内方法共用连接
传播行为处理 支持REQUIREDREQUIRES_NEW等传播行为,灵活控制事务范围
异常兼容 封装数据库异常为Spring统一的TransactionException,简化异常处理

四、AOP+事务管理器的完整执行流程(Spring原生)

结合前面的分析,梳理Spring中AOP实现事务的完整流程:

  1. 启动阶段
    • @EnableTransactionManagement开启事务注解驱动;
    • Spring扫描@Transactional注解,为目标类创建动态代理;
    • 注册TransactionInterceptor(事务拦截器,实现MethodInterceptor)。
  2. 运行阶段
  3. Controller调用业务方法 → 代理对象拦截方法调用;
  4. 触发TransactionInterceptor.invoke()
  5. 调用TransactionManager.getTransaction()开启事务;
  6. TransactionManager获取连接+关闭autoCommit
  7. 执行原始业务方法;
  8. 业务执行成功 → TransactionManager.commit()提交事务;
  9. 业务执行异常 → TransactionManager.rollback()回滚事务;
  10. 释放连接+恢复autoCommit
  11. 返回结果给Controller。

五、常见问题与核心注意点

  1. 事务失效的核心原因
    • 方法非public(AOP无法拦截非public方法);
    • 内部调用(代理对象无法拦截,如service.a()调用service.b()b()的事务失效);
    • 线程池异步调用(不同线程无法共享ThreadLocal中的连接);
    • 异常被捕获(未抛出到拦截器,无法触发回滚)。
  2. ThreadLocal的核心作用
    没有ThreadLocal,不同方法会获取不同的数据库连接,事务无法覆盖多个方法(这是事务管理的核心!)。
  3. 传播行为的本质
    传播行为是通过判断当前线程是否已有事务连接,决定"新建连接"或"复用连接"。

六、学习建议

  1. 先运行手写版代码,理解"注解+AOP+事务管理器+ThreadLocal"的核心;
  2. 阅读Spring源码:
    • 入口:TransactionInterceptor.invoke()
    • 核心类:DataSourceTransactionManagerTransactionSynchronizationManager
  3. 调试事务失效场景(如内部调用、异常捕获),加深对代理和线程绑定的理解。

总结

Spring中AOP实现事务管理的核心流程可总结为:首先通过@EnableTransactionManagement开启事务注解驱动,Spring扫描到业务方法上的@Transactional注解后,为目标业务类创建动态代理对象;当调用方触发标注了@Transactional的业务方法时,实际调用的是代理对象的方法,此时AOP的事务拦截器(TransactionInterceptor)会触发环绕通知逻辑------先调用事务管理器(如DataSourceTransactionManager)的getTransaction()方法,从数据源获取连接并通过ThreadLocal绑定到当前线程,关闭连接的自动提交以开启事务;接着执行原始的业务方法逻辑,若业务执行无异常,事务管理器调用commit()提交事务,若抛出符合回滚规则的异常,则调用rollback()回滚事务;最后无论提交或回滚,都会释放数据库连接、恢复连接的自动提交状态,并清空ThreadLocal中的事务信息,整个过程通过AOP的代理和环绕通知,将事务的开启、提交/回滚逻辑与业务代码解耦,保证业务方法的原子性。

相关推荐
阿杰 AJie几秒前
Token 管理工具
java·spring
Mars酱5 分钟前
1分钟了解响应式编程 | 合适的架构调整
java·后端·响应式编程
yangminlei9 分钟前
Spring Boot/Spring MVC核心注解深度解析
spring boot
浪客川10 分钟前
【百例RUST - 005】所有权和切片
开发语言·后端·rust
ChildrenGreens16 分钟前
otel-collector全家桶
后端
goodlook012316 分钟前
监控平台搭建-日志-springboot直接推送loki篇(九)
java·spring boot·后端·grafana
lfwh17 分钟前
Java 中基于 DBSCAN 算法的车辆交汇点计算实现详解
java·开发语言·算法
老土豆豆豆18 分钟前
你们Agent如何实现Code-Execution的?或许Agent-Sandbox也是你们需要的
后端
数据大魔方20 分钟前
【期货量化入门】期权交易入门:从零开始学期权量化(TqSdk完整教程)
数据库·python·mysql·算法·区块链·程序员创富
虫小宝30 分钟前
导购APP高可用数据库设计:主从分离与分库分表在返利系统中的应用
android·数据库