当前位置: 首页 > news >正文

@Transactional 事务注解

@Transactional 事务注解

  • 1. @Transactional 是什么?
  • 2. @Transactional什么时候使用?
  • 3. @Transactional 的核心原理
  • 4. 常见属性
    • 4.1 propagation (事务传播行为)
    • 4.2 isolation (隔离级别)
    • 4.3 timeout
    • 4.4 readOnly
    • 4.5 rollbackFor / rollbackForClassName
    • 4.6 noRollbackFor / noRollbackForClassName
  • 5. 默认回滚机制
  • 6. 示例代码
  • 7. 常见坑点
    • 7.1 事务方法调用自身不会生效
  • 8. 最佳实践
  • 9. 举例事务不生效
  • 附录

1. @Transactional 是什么?

  • @TransactionalSpring 提供的事务注解,用于声明式事务管理。
  • 它可以用在 方法(public) 上,用来声明该方法/类中的数据库操作需要在事务中执行。
  • 当方法执行过程中出现异常时,可以根据配置进行 事务回滚,保证数据一致性。

2. @Transactional什么时候使用?

以下场景建议使用 @Transactional:
当你需要执行多个数据库操作,且这些操作必须具备原子性(要么全部成功,要么全部失败)。

  • 需要在出现错误或异常时自动回滚操作。
  • 希望避免手动管理事务(比如直接使用 JDBC 或 EntityManager 的事务 API)。

3. @Transactional 的核心原理

Spring 的事务管理主要基于 AOP(面向切面编程) + 数据库的事务支持。

  1. 代理机制
  • Spring 为标注了 @Transactional 的方法生成一个代理类。
  • 在方法执行前,代理类会开启事务;执行后,提交或回滚事务。
  1. 事务管理器
  • Spring 使用 PlatformTransactionManager 来统一管理事务(如 DataSourceTransactionManager 对 JDBC,JpaTransactionManager 对 JPA)。
  1. 数据库事务
  • 最终还是依赖数据库本身的事务机制(ACID)。

4. 常见属性

4.1 propagation (事务传播行为)

定义方法在事务环境中的运行方式。常见值:

传播行为说明
REQUIRED(默认)如果存在事务,加入当前事务;没有事务则新建一个。
REQUIRES_NEW不管是否有事务,都会新建一个事务;原事务会挂起。
SUPPORTS有事务就加入,没有就以非事务方式运行。
NOT_SUPPORTED总是非事务运行,如果有事务则挂起。
MANDATORY必须在事务中运行,否则抛异常。
NEVER必须在非事务中运行,否则抛异常。
NESTED嵌套事务(依赖于 JDBC 的 savepoint 实现),内层回滚不影响外层。

4.2 isolation (隔离级别)

定义事务之间数据访问的隔离性。对应数据库隔离级别:

隔离级别说明
DEFAULT(默认)使用数据库默认隔离级别。
READ_UNCOMMITTED允许读取未提交数据(脏读)。
READ_COMMITTED只能读取已提交数据(避免脏读)。
REPEATABLE_READ多次读取结果一致(避免脏读、不可重复读)。
SERIALIZABLE串行执行事务,避免所有并发问题,但效率最低。

4.3 timeout

  • 事务超时时间(秒),默认使用数据库默认超时。
  • 超时后事务会回滚。

4.4 readOnly

  • true:只读事务,通常用于查询。
  • 提示数据库优化器可优化,不会修改数据。

4.5 rollbackFor / rollbackForClassName

  • 指定遇到哪些 异常类 时回滚事务(默认只对运行时异常 RuntimeException 回滚)。

4.6 noRollbackFor / noRollbackForClassName

  • 指定遇到哪些异常时 不回滚。

5. 默认回滚机制

  • 默认情况下:

    • 运行时异常(RuntimeException)和 Error → 会回滚。
    • 受检异常(CheckedException) → 不会回滚。
  • 可以通过 rollbackFor 来修改默认规则。

6. 示例代码

@Service
public class UserService {@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED,rollbackFor = Exception.class,timeout = 5)public void registerUser(User user) {userMapper.insert(user);// 可能抛出异常if (user.getName() == null) {throw new IllegalArgumentException("用户名不能为空");}accountMapper.createAccount(user.getId());}
}

7. 常见坑点

  1. 事务方法调用自身不会生效

    • 因为事务依赖代理,内部调用不会经过代理,所以事务不起作用。
    • 解决办法:将方法拆到不同的 @Service 类,或者通过 AopContext.currentProxy() 调用。
  2. private 方法不生效

    • Spring AOP 只能代理 public 方法,private/protected 方法不会被增强。
  3. 异步方法事务不生效

    • 异步调用(@Async)会新建线程,不在同一个事务上下文。
  4. 只读事务不是强制的

    • readOnly = true 并不会阻止写操作,只是数据库可能做优化。
  5. 被用 final 、static 修饰的方法上加 @Transactional 也不会生效。

7.1 事务方法调用自身不会生效

@Service
public class UserService {@Transactionalpublic void addUser() {// 插入用户saveUser();// 调用另一个事务方法updateUser();}@Transactionalpublic void updateUser() {// 更新用户}
}

问题:内部调用不会走代理
addUser() 里调用 updateUser() 时,调用方式是:

this.updateUser();
  • 这里的 this 是当前对象(原始对象),不是代理对象。
  • 因此,Spring 的 AOP 拦截器(TransactionInterceptor)不会介入。
  • 结果:updateUser() 上的 @Transactional 不会生效,只是普通方法调用。
  1. 如果 addUser() 没有 @Transactional,但 updateUser() 有:
    • 从外部调用 addUser() 时,updateUser() 的事务不会生效。
  2. 如果 addUser() 有事务,updateUser() 也有事务:
    • 实际上,整个调用都在 addUser() 的事务中,updateUser() 的传播行为被忽略。

解决办法

@Service
public class UserService {@Autowiredprivate UserHelperService helper;@Transactionalpublic void addUser() {saveUser();// 可以解决自身调用事务不生效的问题,本质是通过 代理对象 调用SpringUtils.getBean(UserService.class).updateUser()}
}@Service
public class UserHelperService {@Transactionalpublic void updateUser() {// 更新逻辑}
}

8. 最佳实践

  • 事务边界尽量放在 Service 层(而不是 Controller/DAO)。
  • 保持事务尽量短小,避免长时间占用锁。
  • 明确指定 rollbackFor,避免因受检异常导致事务未回滚。
  • 避免在事务中调用远程服务(如 HTTP、RPC),防止长事务。

9. 举例事务不生效

在这里插入图片描述


解决问题方法
在这里插入图片描述

附录

1.Spring @Transactional 详解:何时使用、为什么使用、如何使用 https://mp.weixin.qq.com/s/pbJllQXG9yN5liiJ6Ywbsw
2.工作 6 年,@Transactional 注解用的一塌糊涂! https://mp.weixin.qq.com/s/Tv0juKbCFqSyXedM2tO3hA

http://www.dtcms.com/a/405963.html

相关文章:

  • PaddleLabel百度飞桨Al Studio图像标注平台安装和使用指南(包冲突 using the ‘flask‘ extra、眼底医疗分割数据集演示)
  • 锦州网站建设工作如何快速网络推广
  • 科技网站建设公司wordpress必做
  • Webpack5 第二节
  • npm、pnpm、npx 三者的定位、核心差异和「什么时候该用谁」
  • 在 C# .NETCore 中使用 MongoDB(第 2 部分):使用过滤子句检索文档
  • AWS Quicksight实践:从零到可视化分析
  • 微服务注册中心 Spring Cloud Eureka是什么?
  • websocket链接
  • 【oceanbase】Oracle模式查看pl慢sql
  • 电子商务网站规划的流程网站备案申请模板
  • 旺道网站优化公众号怎么推广
  • 内存卡标识全解析:从存储到性能的密码
  • 动态的魔法:列表与条件渲染
  • 乐清联科网站建设wordpress divi 数据
  • ARM单片机中断及中断优先级管理详解
  • python软件操作
  • c++_day2
  • 数据通信与计算机网络-交换
  • 2026考研时间,定了
  • 转:Ubuntu20.04安装NVIDIA驱动+CUDA超详细安装指南
  • 软件系统设计课程-Day1-从用户投诉到系统需求
  • 飞浪网站建设网站开发毕业设计任务书
  • JavaScript学习笔记(十二):call、apply和bind使用指南
  • Java外功基础(1)——Spring Web MVC
  • 【双机位A卷】华为OD笔试之【DP】双机位A-构建数列【Py/Java/C++/C/JS/Go六种语言】【欧弟算法】全网注释最详细分类最全的华子OD真题题解
  • 基于PyTorch深度学习无人机遥感影像目标检测、地物分类及语义分割实践技术应用
  • 基于PyTorch深度学习遥感影像地物分类与目标检测、分割及遥感影像问题深度学习优化实践技术应用
  • Kafka如何保证消息可靠性
  • 前端面经-高级开发(华为od)