Java面试题45:一文深入了解Spring 事务原理

一、事务基础核心概念

1.1 什么是事务?

事务是一组数据库操作的最小执行单元 ,这组操作要么全部成功提交 ,要么全部失败回滚,保证数据的一致性。

1.2 事务的 ACID 四大特性(面试必考)

  1. 原子性(Atomicity):事务不可分割,要么全执行,要么全不执行
  2. 一致性(Consistency):事务执行前后,数据的完整性约束不变
  3. 隔离性(Isolation):并发事务之间互不干扰
  4. 持久性(Durability):事务提交后,数据永久生效,不会丢失

1.3 Spring 事务的定位

Spring 事务是对底层数据库事务的封装 ,提供声明式事务 (极简注解)和编程式事务(手动控制)两种实现,屏蔽了底层数据库连接的复杂性,让开发者专注业务逻辑。

二、Spring 事务核心实现原理

2.1 两种事务实现方式

2.2 Spring 事务底层核心原理

  1. 基于 AOP 动态代理实现 Spring 事务本质是 AOP 环绕通知
    • 目标方法执行前:开启事务
    • 目标方法正常执行:提交事务
    • 目标方法抛异常:回滚事务
  2. 核心组件
    • PlatformTransactionManager:事务管理器(真正操作事务的核心接口)
    • TransactionDefinition:事务定义(传播行为、隔离级别、超时时间等)
    • TransactionStatus:事务运行状态
  3. 代理机制
    • JDK 动态代理:代理接口
    • CGLIB 代理:代理普通类

关键结论只有代理对象调用方法,才会触发事务!

三、Spring 事务传播行为

事务传播行为:多个事务方法相互调用时,事务如何传递 / 合并 / 新建 ,Spring 共定义7 种传播行为 ,由Propagation枚举定义。

3.1 7 种传播行为详解

3.2 核心传播行为重点区分

  1. REQUIRED vs REQUIRES_NEW
    • REQUIRED:同一个事务,一起提交 / 回滚
    • REQUIRES_NEW:独立事务,互不干扰
  2. NESTED vs REQUIRES_NEW
    • NESTED:依赖父事务,父回滚子必回滚
    • REQUIRES_NEW:完全独立,父子事务无关联

四、Spring 事务隔离级别

事务隔离级别是数据库层面 的规范,Spring 仅做封装,用于解决脏读、不可重复读、幻读三大并发问题。

4.1 三大并发问题

  1. 脏读 :一个事务读到另一个事务未提交的修改数据
  2. 不可重复读 :同一事务内,两次查询结果不一致(update导致)
  3. 幻读 :同一事务内,两次查询行数不一致(insert/delete导致)

4.2 4 种隔离级别(Spring 对应数据库标准)

4.3 Spring 配置方式

java 复制代码
@Transactional(isolation = Isolation.REPEATABLE_READ)

五、Spring 事务异常处理(回滚规则,面试高频)

5.1 Spring 默认回滚规则

只回滚:运行时异常(RuntimeException)、错误(Error)

不回滚:编译时异常(Checked Exception,如 IOException、SQLException)

5.2 自定义回滚规则

通过rollbackFor/noRollbackFor指定回滚异常:

TypeScript 复制代码
// 所有异常都回滚
@Transactional(rollbackFor = Exception.class)
// 指定异常不回滚
@Transactional(noRollbackFor = BusinessException.class)

5.3 事务不回滚的核心原因

  1. 抛出Checked 异常 且未配置rollbackFor
  2. 异常被try-catch 捕获,未抛出
  3. 非代理对象调用(内部方法调用)
  4. 方法不是 public 修饰

六、Spring 事务常用注解与使用方法

6.1 @Transactional核心属性全解

TypeScript 复制代码
@Transactional(
    propagation = Propagation.REQUIRED, // 传播行为
    isolation = Isolation.REPEATABLE_READ, // 隔离级别
    timeout = 30, // 超时时间(秒)
    readOnly = false, // 是否只读事务
    rollbackFor = Exception.class, // 回滚异常
    noRollbackFor = RuntimeException.class // 不回滚异常
)

6.2 @Transactional使用规范

  1. 只能作用于 public 方法(private/static/final 方法事务失效)
  2. 类 / 接口级别:当前类所有 public 方法生效
  3. 方法级别:优先级高于类级别
  4. 不能作用于静态方法、私有方法

6.3 编程式事务(精准控制)

TypeScript 复制代码
@Autowired
private TransactionTemplate transactionTemplate;

public void testTransaction() {
    transactionTemplate.execute(status -> {
        // 业务逻辑
        userMapper.insert(user);
        return true;
    });
}

七、Spring 事务常见使用场景

7.1 单数据源常规事务(最常用)

TypeScript 复制代码
@Service
public class OrderService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private StockMapper stockMapper;

    // 下单+扣库存,原子操作
    @Transactional(rollbackFor = Exception.class)
    public void createOrder(Order order) {
        orderMapper.insert(order);
        stockMapper.deductStock(order.getGoodsId());
    }
}

7.2 嵌套事务场景

TypeScript 复制代码
@Transactional
public void parent() {
    // 主业务
    child();
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void child() {
    // 子业务独立事务
}

7.3 只读事务(查询优化)

TypeScript 复制代码
@Transactional(readOnly = true)
public List<User> getUserList() {
    return userMapper.selectList();
}

只读事务作用:数据库优化、防止误写、提升查询性能

八、Spring 事务经典问题 + 解决方案

8.1 @Transactional事务失效场景

内部调用失效解决方案(最常用)

TypeScript 复制代码
@Service
public class TestService {
    // 注入自身代理对象
    @Autowired
    private TestService testService;

    public void methodA() {
        // 错误:this.methodB() 事务失效
        // 正确:代理对象调用
        testService.methodB();
    }

    @Transactional
    public void methodB() {
        // 业务逻辑
    }
}

8.2 事务不回滚解决方案

  1. 检查异常是否为RuntimeException/Error
  2. 检查是否try-catch 吞了异常
  3. 检查是否配置rollbackFor = Exception.class
  4. 检查是否代理对象调用

8.3 嵌套事务数据不一致

使用REQUIRES_NEW保证子事务独立,避免父事务回滚影响子事务。

九、Spring 事务高频面试题

  1. Spring 事务的传播行为有哪些?默认是什么?
  2. @Transactional注解失效的场景有哪些?
  3. Spring 事务默认回滚什么异常?为什么不回滚 Checked 异常?
  4. Spring 事务的隔离级别有哪些?解决什么问题?
  5. REQUIRED 和 REQUIRES_NEW 的区别?
  6. Spring 事务的底层实现原理?
  7. 什么是声明式事务和编程式事务?区别是什么?
  8. 只读事务的作用是什么?
  9. 事务挂起是什么意思?
  10. NESTED 和 REQUIRES_NEW 的区别?

十、总结

  1. Spring 事务基于 AOP 动态代理实现,代理对象调用才生效
  2. 传播行为REQUIRED是默认值,满足 90% 业务场景
  3. 隔离级别REPEATABLE_READ(MySQL 默认)解决脏读、不可重复读
  4. @Transactional只作用于 public 方法,异常被 catch 会导致不回滚
  5. 开发核心避坑:避免内部调用、异常不要吞、指定 rollbackFor
相关推荐
重庆兔巴哥2 小时前
Java环境变量配置不成功,会有什么症状?
java·开发语言
cjy0001112 小时前
Spring学习——新建module模块
java·学习·spring
zhougl9962 小时前
Maven 依赖分离
java·maven
重庆兔巴哥2 小时前
如何安装和配置Java开发环境(JDK)?
java·开发语言
鸽鸽程序猿2 小时前
【Java EE】【SpringAI】智能聊天机器人
java·java-ee·机器人
sthnyph2 小时前
Spring Framework 中文官方文档
java·后端·spring
带刺的坐椅2 小时前
Snack4 Json 流式解析与自动结构修复深度指南
java·llm·json·jsonpath
zb200641202 小时前
Spring Boot 实战篇(四):实现用户登录与注册功能
java·spring boot·后端
我命由我123452 小时前
Android 多进程开发 - FileDescriptor、Uri、AIDL 接口定义不能抛出异常
android·java·java-ee·kotlin·android studio·android-studio·android runtime