Spring 事务常见面试题

111 阅读6分钟

首先我们要明白Spring 事务是什么?

Spring 事务是 Spring 框架提供的事务管理机制,用于保证数据库操作的原子性、一致性、隔离性和持久性(ACID 特性) 。它简化了传统 Java EE 中复杂的事务管理(如手动编写 try-catch 控制事务),通过声明式或编程式方式,让开发者更专注于业务逻辑。

常见面试题及解析

1. Spring 事务的核心特性是什么?

Spring 事务的核心是保证数据库操作的ACID 特性

  • 原子性(Atomicity) :事务中的操作要么全部成功,要么全部失败(回滚)。
  • 一致性(Consistency) :事务执行前后,数据库状态始终符合业务规则(如转账后总金额不变)。
  • 隔离性(Isolation) :多个并发事务之间相互隔离,避免干扰(如脏读、不可重复读、幻读)。
  • 持久性(Durability) :事务提交后,数据修改永久保存到数据库。

2. Spring 事务的管理方式有哪些?

Spring 支持两种事务管理方式:

  • 编程式事务:通过代码手动控制事务(如TransactionTemplatePlatformTransactionManager),灵活性高但侵入性强。

    java

    运行

    @Autowired
    private TransactionTemplate transactionTemplate;
    
    public void doBusiness() {
        transactionTemplate.execute(status -> {
            // 业务逻辑
            return null;
        });
    }
    
  • 声明式事务:通过注解(@Transactional)或 XML 配置声明事务,非侵入式,是实际开发的首选。

    java

    运行

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

3. @Transactional注解的核心属性有哪些?

@Transactional的常用属性用于控制事务行为:

  • propagation:事务传播行为(如REQUIREDREQUIRES_NEW,控制多个事务方法调用时的事务关系)。
  • isolation:事务隔离级别(如READ_COMMITTED,控制并发事务的隔离程度)。
  • timeout:事务超时时间(默认 - 1,永不超时,单位秒)。
  • readOnly:是否为只读事务(若为true,数据库可优化性能,适用于查询操作)。
  • rollbackFor:指定哪些异常触发回滚(默认只回滚RuntimeExceptionError)。
  • noRollbackFor:指定哪些异常不触发回滚。

4. 事务传播行为有哪些?最常用的是哪两个?

事务传播行为定义了当一个事务方法调用另一个事务方法时,事务如何传播(是否共用一个事务,还是新建事务)。Spring 定义了 7 种传播行为:

  • REQUIRED(默认):如果当前有事务,则加入;否则新建事务。

  • REQUIRES_NEW:无论当前是否有事务,都新建一个事务(原事务暂停)。

  • SUPPORTS:如果当前有事务,则加入;否则以非事务方式执行。

  • MANDATORY:必须在事务中执行,否则抛异常。

  • NOT_SUPPORTED:以非事务方式执行,若当前有事务则暂停。

  • NEVER:以非事务方式执行,若当前有事务则抛异常。

  • NESTED:如果当前有事务,则嵌套在当前事务中(仅部分数据库支持,如 MySQL 的 Savepoint)。

最常用REQUIRED(大多数业务场景)和REQUIRES_NEW(需要独立事务的场景,如日志记录)。

5. 事务隔离级别有哪些?Spring 默认的隔离级别是什么?

隔离级别解决并发事务中的脏读、不可重复读、幻读问题,Spring 定义了 5 种(对应数据库标准):

  • DEFAULT(默认):使用数据库默认隔离级别(如 MySQL 默认REPEATABLE_READ,Oracle 默认READ_COMMITTED)。

  • READ_UNCOMMITTED:允许读取未提交的数据(可能脏读、不可重复读、幻读)。

  • READ_COMMITTED:只能读取已提交的数据(避免脏读,可能不可重复读、幻读)。

  • REPEATABLE_READ:保证多次读取同一数据一致(避免脏读、不可重复读,可能幻读)。

  • SERIALIZABLE:最高隔离级别,事务串行执行(避免所有问题,但性能极差)。

Spring 默认隔离级别DEFAULT(依赖数据库)。

6. @Transactional注解不生效的常见场景有哪些?

  1. 方法不是 public@Transactional默认只对 public 方法生效(非 public 方法事务不生效)。

  2. 自调用问题:同一个类中,非事务方法调用事务方法(因 Spring AOP 代理特性,事务不生效)。

    java

    运行

    public class Service {
        public void methodA() {
            methodB(); // 自调用,methodB的@Transactional不生效
        }
        
        @Transactional
        public void methodB() {}
    }
    
  3. 异常被捕获:事务方法中异常被try-catch捕获且未重新抛出,Spring 无法感知异常,不会回滚。

  4. 错误的异常类型:默认只回滚RuntimeExceptionError,若抛出 checked 异常(如IOException)且未通过rollbackFor指定,事务不回滚。

  5. 数据库不支持事务:如使用 MySQL 的 MyISAM 引擎(不支持事务),需改为 InnoDB。

  6. 注解加在接口或父类上:若代理方式为 CGLIB(代理类),接口上的@Transactional可能不生效(建议加在实现类方法上)。

7. Spring 事务的实现原理是什么?

Spring 事务基于AOP(面向切面编程)  和动态代理实现:

  • 当方法标注@Transactional时,Spring 通过 AOP 生成代理对象,在方法执行前后插入事务管理逻辑(开启、提交、回滚)。
  • 代理方式:若目标类实现接口,默认用JDK 动态代理;否则用CGLIB 代理(需配置proxyTargetClass=true)。
  • 核心接口:PlatformTransactionManager(事务管理器,如DataSourceTransactionManager用于 JDBC 事务)。

8. 什么是事务的 “脏读、不可重复读、幻读”?如何解决?

  • 脏读:事务 A 读取到事务 B 未提交的修改(B 可能回滚,导致 A 读错)。
    解决:隔离级别至少READ_COMMITTED
  • 不可重复读:事务 A 多次读取同一数据,期间事务 B 修改并提交,导致 A 两次读取结果不一致。
    解决:隔离级别至少REPEATABLE_READ
  • 幻读:事务 A 按条件查询,期间事务 B 新增符合条件的数据并提交,导致 A 再次查询时多了 “幻影” 数据。
    解决:隔离级别SERIALIZABLE(或通过数据库锁机制,如 MySQL 的 Next-Key Lock)。

9. 如何实现分布式事务?Spring 有哪些方案?

分布式事务指跨多个数据库(或服务)的事务(如微服务中订单服务和库存服务的操作)。Spring 相关方案:

  • 2PC(两阶段提交) :基于JtaTransactionManager,依赖分布式事务协调器(如 Atomikos),但性能差、可用性低。
  • TCC(Try-Confirm-Cancel) :业务层实现三个接口(尝试、确认、取消),如 Seata 的 TCC 模式。
  • Saga 模式:将分布式事务拆分为本地事务序列,通过补偿机制回滚,适用于长事务。
  • 本地消息表:基于消息队列实现最终一致性(如 RocketMQ 的事务消息)。

10. @TransactionalreadOnly=true有什么作用?

  • 标记事务为只读事务,告诉数据库此事务只做查询,不做修改。
  • 数据库可优化性能(如 MySQL 的 InnoDB 会避免加锁,提高查询效率)。
  • 若在readOnly=true的事务中执行写操作,可能抛异常(取决于数据库)。