跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava

Spring @Transactional 注解详解

Spring @Transactional 注解是声明式事务管理的核心,通过 AOP 实现业务与事务解耦。其基本用法、主要属性(传播行为、隔离级别、超时等)、工作原理及常见失效原因(如自调用、异常捕获)。涵盖多数据源配置、最佳实践总结,帮助开发者掌握事务控制机制,避免数据不一致问题。

极光发布于 2026/3/16更新于 2026/5/3129 浏览
Spring @Transactional 注解详解

在 Spring 框架中,@Transactional 注解是声明式事务管理的核心。它允许开发者通过简单的注解配置,将事务管理逻辑从业务代码中剥离,极大地简化了事务控制。

1. 什么是 @Transactional

@Transactional 是 Spring 提供的声明式事务管理注解,用于标识方法或类需要被事务管理。当标注了该注解的方法被调用时,Spring 会在方法执行前开启事务,方法执行后根据是否抛出异常来决定提交或回滚事务。

作用:

  • 简化事务代码:无需手动管理 Connection 或 Transaction 对象。
  • 声明式事务:通过 AOP 实现,业务代码与事务逻辑解耦。
  • 灵活配置:支持事务传播行为、隔离级别、超时、只读等属性。

2. 基本用法

2.1 在方法上使用
@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    @Transactional
    public void createUser(User user) {
        userMapper.insert(user);
        // 其他业务操作...
    }
}
2.2 在类上使用
@Service
@Transactional
public class UserService {
    // 类中的所有 public 方法都将被事务管理
}
  • 标注在类上时,该类的所有 public 方法都会被事务管理。
  • 方法上的注解会覆盖类上的注解。
2.3 注意事项
  • 默认情况下,只有 public 方法才支持 @Transactional。如果标注在 protected、private 或包可见的方法上,Spring 不会应用事务(但不会报错,只是无效)。
  • 必须通过 Spring 代理对象调用方法,直接调用(如 this.createUser(...))会导致事务失效。

3. 主要属性详解

@Transactional 提供了丰富的属性,用于精细控制事务行为。

属性类型说明
value / transactionManagerString指定使用的事务管理器 Bean 名称,用于多数据源场景。
propagationPropagation事务传播行为,指定方法如何参与已有事务。
isolationIsolation事务隔离级别,定义事务之间的隔离程度。
timeoutint事务超时时间(秒),默认 -1(使用底层事务系统默认超时)。
readOnlyboolean是否为只读事务,默认 false。可优化数据库资源。
rollbackForClass<? extends Throwable>[]指定哪些异常触发事务回滚。
rollbackForClassNameString[]异常类名形式。
noRollbackForClass<? extends Throwable>[]指定哪些异常不触发事务回滚。
noRollbackForClassNameString[]异常类名形式。
3.1 value / transactionManager

当应用中有多个 PlatformTransactionManager 时,通过该属性指定使用哪个事务管理器。

@Transactional("orderTransactionManager")
public void processOrder() {
    ...
}
3.2 propagation(传播行为)
传播行为说明
REQUIRED(默认 required)如果当前存在事务,则加入该事务;如果没有,则新建一个事务。
SUPPORTS(support)如果当前存在事务,则加入;否则以非事务方式执行。
MANDATORY(mandatory)强制要求当前存在事务,否则抛出异常。
REQUIRES_NEW(requires_new)新建一个事务,如果当前存在事务,则挂起当前事务。
NOT_SUPPORTED(not_supported)以非事务方式执行,如果当前存在事务,则挂起它。
NEVER(never)以非事务方式执行,如果当前存在事务,则抛出异常。
NESTED(nested)如果当前存在事务,则在嵌套事务内执行;否则行为类似 REQUIRED。

解析:

  • REQUIRES_NEW 内部事务的提交/回滚不影响外部事务,反之亦然。
  • NESTED 依赖于底层数据库的保存点(savepoint)支持,允许部分回滚。并非所有数据库都支持。
3.3 isolation(隔离级别)
隔离级别说明
DEFAULT使用底层数据库的默认隔离级别。
READ_UNCOMMITTED允许读取未提交的数据(脏读、不可重复读、幻读都可能发生)。
READ_COMMITTED只能读取已提交的数据(避免脏读,但可能发生不可重复读和幻读)。
REPEATABLE_READ同一事务内多次读取结果一致(避免脏读和不可重复读,但可能幻读)。
SERIALIZABLE最高级别,事务串行执行,避免所有并发问题,但性能最差。
3.4 timeout

设置事务的超时秒数。超过时间,事务会自动回滚。

3.5 readOnly

标记事务为只读,有助于数据库优化(如 Oracle 会跳过锁获取),但需确保事务内没有写操作。

3.6 rollbackFor / noRollbackFor

默认情况下,Spring 事务只在遇到运行时异常(RuntimeException 及其子类)和 Error 时回滚,检查型异常(如 IOException)不会触发回滚。通过 rollbackFor 可以指定某些检查异常也应回滚,或通过 noRollbackFor 指定某些运行时异常不回滚。

@Transactional(rollbackFor = Exception.class)
// 任何异常都回滚
public void update() throws Exception {
    // ...
}

@Transactional(noRollbackFor = IllegalArgumentException.class)
public void process() {
    // ...
}

4. 工作原理:Spring 声明式事务的实现机制

Spring 的声明式事务基于 AOP(面向切面编程) 实现,核心组件包括:

  1. 事务管理器(PlatformTransactionManager):如 DataSourceTransactionManager、JpaTransactionManager。
  2. 事务拦截器(TransactionInterceptor):AOP 增强,负责在目标方法前后执行事务逻辑。
  3. 事务属性来源(TransactionAttributeSource):解析 @Transactional 注解,获取事务配置。
  4. 代理对象:通过 JDK 动态代理或 CGLIB 生成代理对象,包裹目标方法。
4.1 执行流程
  1. 调用方获取的是 Spring 生成的代理对象(而非原始 Bean)。
  2. 代理对象中的 TransactionInterceptor 在方法调用前,根据 @Transactional 配置开启事务。
  3. 执行目标方法(业务逻辑)。
  4. 方法执行后:
    • 如果方法正常返回,则提交事务。
    • 如果方法抛出异常,根据配置决定回滚或提交。
  5. 最终返回结果给调用方。
4.2 源码层面
  • TransactionInterceptor 实现 MethodInterceptor,在 invoke() 方法中调用 invokeWithinTransaction()。
  • invokeWithinTransaction() 根据事务管理器、传播行为等处理事务开启、提交、回滚。

5. 事务不生效的常见原因

5.1 自调用问题
@Service
public class UserService {
    public void outer() {
        inner(); // 直接调用,this 是原始对象,而非代理对象
    }

    @Transactional
    public void inner() {
        // 数据库操作
    }
}

原因:outer() 中的 inner() 是通过 this 直接调用的,没有经过代理对象,因此事务注解无效。

解决方法:

  • 将方法拆分为不同 Bean,通过注入调用。
  • 使用 AopContext.currentProxy() 获取当前代理对象:
((UserService) AopContext.currentProxy()).inner();

需要配置 @EnableAspectJAutoProxy(exposeProxy = true)。

5.2 方法不是 public

@Transactional 默认只对 public 方法生效。如果标注在非 public 方法上,Spring 不会应用事务。

5.3 数据库不支持事务

例如 MySQL 的 MyISAM 引擎不支持事务,需要使用 InnoDB。

5.4 事务管理器未配置或配置错误

Spring Boot 默认会配置事务管理器,但多数据源时需要显式指定。

5.5 异常被捕获
@Transactional
public void method() {
    try {
        // 数据库操作
        throw new RuntimeException();
    } catch (Exception e) {
        // 异常被捕获,没有抛出
    }
}

事务拦截器无法感知异常,因此不会回滚。解决方法:在 catch 块中重新抛出异常,或通过 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly() 手动标记回滚。

5.6 传播行为配置不当

例如在 REQUIRED 传播下,内部事务抛异常,外部事务也回滚;但在 REQUIRES_NEW 下,内部事务回滚不会影响外部事务。

6. 事务传播行为实践案例

6.1 REQUIRED(默认)
@Service
public class OuterService {
    @Autowired
    private InnerService innerService;

    @Transactional
    public void outer() {
        innerService.inner(); // 加入外部事务
        // 如果 inner 抛异常,outer 也会回滚
    }
}

@Service
public class InnerService {
    @Transactional(propagation = Propagation.REQUIRED)
    public void inner() {
        // 数据库操作
    }
}
6.2 REQUIRES_NEW
@Service
public class OuterService {
    @Autowired
    private InnerService innerService;

    @Transactional
    public void outer() {
        innerService.inner(); // 新事务
        // inner 回滚不影响 outer
    }
}

@Service
public class InnerService {
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void inner() {
        // 数据库操作
    }
}
6.3 NESTED(需要数据库支持保存点)
@Transactional(propagation = Propagation.NESTED)
public void inner() {
    // 如果外部事务存在,则在嵌套事务内执行,可部分回滚
}

7. 隔离级别与并发问题

7.1 并发问题类型
  • 脏读:读取到其他事务未提交的数据。
  • 不可重复读:同一事务内两次读取同一数据,结果不一致(数据被其他事务修改并提交)。
  • 幻读:同一事务内两次查询返回的记录数不同(其他事务插入或删除了记录)。
7.2 隔离级别选择
级别脏读不可重复读幻读
READ_UNCOMMITTED可能可能可能
READ_COMMITTED避免可能可能
REPEATABLE_READ避免避免可能
SERIALIZABLE避免避免避免

注意:MySQL InnoDB 默认使用 REPEATABLE_READ,并通过 MVCC 机制在一定程度上避免了幻读。

8. Spring Boot 中的 @Transactional

8.1 自动配置

Spring Boot 自动配置了 DataSourceTransactionManager 和 JpaTransactionManager,无需额外配置。只需在启动类上添加 @EnableTransactionManagement(实际上 Spring Boot 会自动启用,但显式加上也无妨)。

8.2 多数据源配置
@Bean
@Primary
public PlatformTransactionManager primaryTransactionManager(@Qualifier("primaryDataSource") DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
}

@Bean
public PlatformTransactionManager secondaryTransactionManager(@Qualifier("secondaryDataSource") DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
}

使用时通过 value 属性指定:

@Transactional("secondaryTransactionManager")
public void method() {
    ...
}

9. 最佳实践总结

  1. 明确事务边界:事务应尽量短小,避免在事务内执行耗时的网络请求、文件操作等。
  2. 合理选择传播行为:理解每种传播行为的含义,避免误用导致数据不一致。
  3. 异常处理:不要随意捕获异常而不抛出,否则事务不会回滚。
  4. 只读事务优化:对于只读操作,设置 readOnly=true 可提升性能。
  5. 私有方法无效:确保 @Transactional 标注在 public 方法上。
  6. 自调用问题:通过注入代理对象或使用 AopContext.currentProxy() 解决。
  7. 测试事务:在单元测试中,可使用 @Transactional 和 @Rollback 实现测试数据自动回滚。
  8. 使用默认回滚规则:通常建议所有异常都回滚,除非明确不需要回滚的场景。

10. 总结

@Transactional 是 Spring 声明式事务的核心注解,通过简洁的配置即可实现强大的事务管理。理解其属性、传播行为、隔离级别以及工作原理,对于编写健壮的应用程序至关重要。同时,注意避免常见陷阱(如自调用、异常被吞),才能确保事务按预期生效。

目录

  1. 1. 什么是 @Transactional
  2. 2. 基本用法
  3. 2.1 在方法上使用
  4. 2.2 在类上使用
  5. 2.3 注意事项
  6. 3. 主要属性详解
  7. 3.1 value / transactionManager
  8. 3.2 propagation(传播行为)
  9. 3.3 isolation(隔离级别)
  10. 3.4 timeout
  11. 3.5 readOnly
  12. 3.6 rollbackFor / noRollbackFor
  13. 4. 工作原理:Spring 声明式事务的实现机制
  14. 4.1 执行流程
  15. 4.2 源码层面
  16. 5. 事务不生效的常见原因
  17. 5.1 自调用问题
  18. 5.2 方法不是 public
  19. 5.3 数据库不支持事务
  20. 5.4 事务管理器未配置或配置错误
  21. 5.5 异常被捕获
  22. 5.6 传播行为配置不当
  23. 6. 事务传播行为实践案例
  24. 6.1 REQUIRED(默认)
  25. 6.2 REQUIRES_NEW
  26. 6.3 NESTED(需要数据库支持保存点)
  27. 7. 隔离级别与并发问题
  28. 7.1 并发问题类型
  29. 7.2 隔离级别选择
  30. 8. Spring Boot 中的 @Transactional
  31. 8.1 自动配置
  32. 8.2 多数据源配置
  33. 9. 最佳实践总结
  34. 10. 总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • AI 生成代码时代,人类开发者如何保持创意价值?
  • Visual Studio Code + Continue + Ollama 实现本地 AI 代码助手
  • C/C++ 动态规划实战:从打家劫舍到股票买卖的多状态 DP 解析
  • Qwen3.5-9B 参数量优势与架构分析:对比 GPT-oss-120B 及多模态能力
  • Qt Creator 配置 GitHub Copilot AI 编程插件
  • Stable Diffusion 3 发布:MMDiT 架构与性能解析
  • Mac 开发环境详解:Xcode 作用与安装
  • 谷歌发布乒乓球 AI 机器人,实现正反手灵活转换与中级选手水平对抗
  • pyenv 多环境管理完全指南:Python 版本切换与隔离实战
  • SpringBoot 整合 Langchain4j 实现会话记忆存储深度解析
  • 数据结构实战:并查集应用与优化
  • 从零构建 Python AI Agent:原理与实战
  • WebRTC 架构全景解析:从浏览器 API 到 libwebrtc
  • Vitis 安装实战:从零搭建 FPGA 开发环境
  • 本地 Web 服务器搭建指南:Web Server for Chrome 使用详解
  • 基于 AD7606 的 8 通道高速同步采集系统设计与 Verilog 实现
  • CVPR 2024 Fusion-Mamba 跨模态目标检测论文解读
  • 数据结构:队列核心原理与 C 语言实战
  • Python 爬虫进阶:使用 Scrapy 库进行数据提取和处理
  • 高校毕业论文知网 AIGC 检测标准及降低 AI 率方法

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online