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

【Java开发】Spring 事务开发完全指南:从入门到精通

目录

一、为什么需要事务?从一个真实案例说起

二、Spring 事务核心概念:先搞懂这三个关键组件

2.1 三大核心接口

三、声明式事务:99% 的场景都用它(附完整代码示例)

3.1 最简入门:3 步搞定基础使用

步骤 1:添加依赖(Maven/Gradle)

步骤 2:配置事务管理器(Spring Boot 自动配置,非 Boot 需手动)

步骤 3:在 Service 方法上添加 @Transactional 注解

3.2 @Transactional 注解全参数解析

传播行为深度解析(最容易混淆的点)

四、编程式事务:适合复杂场景的精细控制

4.1 什么时候用编程式事务?

4.2 代码示例:使用 TransactionTemplate

4.3 对比声明式 vs 编程式

五、Spring Boot 事务自动配置:新手也能秒懂的原理

5.1 自动配置流程(图解)

5.2 手动配置 override(进阶)

5.3 事务属性配置(application.properties)

六、事务失效?这 8 个坑 90% 的新手都踩过

6.1 坑 1:方法修饰符不是 public

6.2 坑 2:同一类内方法调用

6.3 坑 3:未处理的检查型异常(Checked Exception)

6.4 坑 4:自动提交未关闭(@Transactional 失效的隐藏原因)

6.5 坑 5:事务管理器未正确注入

6.6 坑 6:使用了错误的事务管理器(多数据源场景)

6.7 坑 7:异常被吞掉(最隐蔽的坑)

6.8 坑 8:类未被 Spring 管理

七、与 MyBatis/JPA 整合:具体场景的最佳实践

7.1 MyBatis 场景:批量操作的事务优化

7.2 JPA 场景:只读事务优化查询性能

7.3 多数据源场景:指定事务管理器

八、分布式事务

8.1 什么是分布式事务?

8.2 三种主流方案对比

8.3 Spring 集成 Seata(最简示例)

九、事务调试与监控:必备的排查技巧

9.1 开启调试日志(关键!)

9.2 常用排查命令

9.3 生产环境监控指标

十、总结


一、为什么需要事务?从一个真实案例说起

假设你正在开发一个电商系统,用户下单时需要同时完成两个操作:

  1. 创建订单记录(插入订单表)
  2. 扣减库存(更新商品表库存字段)

如果没有事务保护,可能会出现以下情况:

  • 订单创建成功,但库存扣减失败
  • 系统突然断电,导致部分操作未持久化
  • 多用户并发下单时,库存出现负数

事务的核心价值:确保这两个操作要么全部成功,要么全部失败,就像一个 "原子操作"。

二、Spring 事务核心概念:先搞懂这三个关键组件

2.1 三大核心接口

(1)PlatformTransactionManager(事务管理器)

  • 作用:管理事务的创建、提交、回滚
  • 常见实现类:
    • DataSourceTransactionManager(用于 JDBC/MyBatis)
    • JpaTransactionManager(用于 JPA/Hibernate)
    • HibernateTransactionManager(旧版 Hibernate 专用)
  • 问题:为什么需要选择不同的实现类?

👉 因为不同持久化框架的事务操作方式不同,比如 JPA 和 MyBatis 的底层连接获取方式有差异

(2)TransactionDefinition(事务定义)

  • 作用:定义事务的属性(隔离级别、传播行为、超时时间等)
  • 核心属性:
public interface TransactionDefinition {int getPropagationBehavior(); // 传播行为(7种)int getIsolationLevel(); // 隔离级别(5种)int getTimeout(); // 超时时间(秒)boolean isReadOnly(); // 是否只读事务
}

(3)TransactionStatus(事务状态)

  • 作用:保存事务运行时的状态(是否新事务、是否已回滚等)
  • 常用方法:
status.isNewTransaction(); // 是否是新创建的事务
status.setRollbackOnly(); // 标记为仅回滚(手动回滚)

三、声明式事务:99% 的场景都用它(附完整代码示例)

3.1 最简入门:3 步搞定基础使用

步骤 1:添加依赖(Maven/Gradle)
<!-- Spring Boot场景 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId> <!-- 包含事务支持 -->
</dependency><!-- 非Spring Boot场景需手动添加 -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>6.0.11</version>
</dependency>

步骤 2:配置事务管理器(Spring Boot 自动配置,非 Boot 需手动)
// Spring Boot自动配置,无需额外代码
// 非Spring Boot场景需在配置类中添加:
@Configuration
public class TransactionConfig {@Beanpublic DataSourceTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}
}

步骤 3:在 Service 方法上添加 @Transactional 注解
@Service
public class OrderService {@Autowiredprivate OrderRepository orderRepository;@Autowiredprivate ProductRepository productRepository;// 核心业务方法,添加事务注解@Transactionalpublic void createOrder(Order order) {// 1. 创建订单orderRepository.save(order);// 2. 扣减库存(假设这里可能抛出异常)productRepository.decreaseStock(order.getProductId(), order.getQuantity());}
}

3.2 @Transactional 注解全参数解析

参数名

作用

默认值

示例

value

限定作用的事务管理器 Bean 名称

空(使用默认管理器)

@Transactional("customTransactionManager")

propagation

事务传播行为(解决多个事务方法嵌套调用的问题)

Propagation.REQUIRED

@Transactional(propagation = Propagation.REQUIRES_NEW)

isolation

事务隔离级别(解决并发事务的数据可见性问题)

Isolation.DEFAULT

@Transactional(isolation = Isolation.READ_COMMITTED)

timeout

事务超时时间(超时则自动回滚)

-1(永不超时)

@Transactional(timeout = 10)

readOnly

标记为只读事务(优化数据库性能)

false

@Transactional(readOnly = true)

rollbackFor

指定需要回滚的异常类型(可多个)

空(仅回滚 RuntimeException)

@Transactional(rollbackFor = {SQLException.class, IOException.class})

rollbackForClassName

同上,通过异常类名指定(字符串形式)

@Transactional(rollbackForClassName = "java.sql.SQLException")

noRollbackFor

指定不需要回滚的异常类型(可多个)

@Transactional(noRollbackFor = BusinessException.class)

noRollbackForClassName

同上,通过异常类名指定(字符串形式)

@Transactional(noRollbackForClassName = "com.example.BusinessException")

传播行为深度解析(最容易混淆的点)

假设存在以下调用关系:

methodA() { ... methodB() ... }

methodA和methodB都添加了 @Transactional 注解,传播行为决定了两者的事务如何关联。

传播行为

英文名称

核心逻辑

典型场景

REQUIRED

必填(默认)

如果当前有事务,加入该事务;否则创建新事务

普通业务方法

REQUIRES_NEW

需要新事务

挂起当前事务,创建新事务执行

独立于外层的子事务(如日志记录)

SUPPORTS

支持事务

如果当前有事务,加入该事务;否则以非事务方式执行

可选事务的查询方法

NOT_SUPPORTED

不支持事务

挂起当前事务,以非事务方式执行

性能优先的只读查询

MANDATORY

强制事务

必须存在当前事务,否则抛出异常

依赖外层事务的子操作

NEVER

禁止事务

必须不存在当前事务,否则抛出异常

绝对不允许事务的场景

NESTED

嵌套事务

在当前事务中创建一个保存点(仅 JDBC 支持,Hibernate 不支持)

可部分回滚的子操作

案例

外层方法A(REQUIRED)调用内层方法B(REQUIRES_NEW):

  • A先创建事务 T1
  • B挂起 T1,创建新事务 T2
  • 如果B抛出异常,T2 回滚,T1 可选择继续执行或回滚

四、编程式事务:适合复杂场景的精细控制

4.1 什么时候用编程式事务?

  • 需要在事务执行过程中动态获取事务状态
  • 需要更细粒度的事务控制(如手动设置回滚)
  • 非注解场景(如第三方框架集成)

4.2 代码示例:使用 TransactionTemplate

@Service
public class OrderService {@Autowiredprivate TransactionTemplate transactionTemplate;@Autowiredprivate OrderRepository orderRepository;@Autowiredprivate ProductRepository productRepository;public void createOrderWithProgrammaticTransaction(Order order) {transactionTemplate.execute(status -> { // 传入TransactionCallbacktry {orderRepository.save(order);productRepository.decreaseStock(order.getProductId(), order.getQuantity());// 主动提交需返回null或正常对象,异常会触发回滚return null;} catch (Exception e) {// 手动标记回滚(可选,抛出异常也会回滚)status.setRollbackOnly(); throw new RuntimeException("事务执行失败", e);}});}
}

4.3 对比声明式 vs 编程式

特性

声明式(@Transactional)

编程式(TransactionTemplate)

学习成本

低(简单注解)

中(需要理解 TransactionCallback)

灵活性

低(固定流程)

高(可控制事务每个阶段)

代码侵入性

低(无额外代码)

中(需要编写回调逻辑)

适用场景

90% 的普通业务场景

复杂控制、非注解场景

五、Spring Boot 事务自动配置:新手也能秒懂的原理

5.1 自动配置流程(图解)

5.2 手动配置 override(进阶)

如果自动配置的事务管理器不满足需求(如多数据源),需手动配置:

@Configuration
public class MultiDataSourceConfig {@Bean(name = "primaryTransactionManager")public DataSourceTransactionManager primaryTransactionManager(@Qualifier("primaryDataSource") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}@Bean(name = "secondaryTransactionManager")public DataSourceTransactionManager secondaryTransactionManager(@Qualifier("secondaryDataSource") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}
}

5.3 事务属性配置(application.properties)

# 全局事务隔离级别(可被方法注解覆盖)
spring.jpa.properties.hibernate.transaction.isolation=READ_COMMITTED# 配置事务超时时间(单位:秒,对所有事务生效)
spring.transaction.default-timeout=30

六、事务失效?这 8 个坑 90% 的新手都踩过

6.1 坑 1:方法修饰符不是 public

@Service
public class UserService {// 错误:protected方法不会被AOP代理@Transactionalprotected void updateUser() { ... }// 错误:private方法无法被代理@Transactionalprivate void deleteUser() { ... }// 正确:public方法@Transactionalpublic void saveUser() { ... }
}

6.2 坑 2:同一类内方法调用

@Service
public class OrderService {// 外部调用有效@Override@Transactionalpublic void createOrder() {saveOrder(); // 内部调用,事务失效!}// 内部方法无注解private void saveOrder() { ... }// 正确做法:通过@Autowired注入自身代理@Autowiredprivate OrderService selfProxy;@Overridepublic void createOrder() {selfProxy.saveOrder(); // 通过代理调用,事务生效}@Transactionalprivate void saveOrder() { ... }
}

6.3 坑 3:未处理的检查型异常(Checked Exception)

@Transactional
public void updateStock() throws IOException {// 抛出检查型异常(非RuntimeException)throw new IOException("库存更新失败"); // 👉 默认不会回滚,因为@Transactional只回滚RuntimeException
}// 修正:显式指定回滚异常
@Transactional(rollbackFor = IOException.class)
public void updateStock() throws IOException {throw new IOException("库存更新失败"); // 现在会回滚
}

6.4 坑 4:自动提交未关闭(@Transactional 失效的隐藏原因)

如果使用 MyBatis,需确保SqlSession关闭自动提交:

// MyBatis配置类(重要!)
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) throws Exception {SqlSessionFactoryBean factory = new SqlSessionFactoryBean();factory.setDataSource(dataSource);// 关闭自动提交,让Spring事务控制提交factory.getObject().getConfiguration().setAutoCommit(false); return factory;
}

6.5 坑 5:事务管理器未正确注入

@Service
public class UserService {// 错误:未注入事务管理器,直接使用会报空指针private TransactionTemplate transactionTemplate;// 正确:通过@Autowired注入@Autowiredprivate TransactionTemplate transactionTemplate;
}

6.6 坑 6:使用了错误的事务管理器(多数据源场景)

// 错误:未指定事务管理器,默认使用第一个创建的
@Transactional
public void updatePrimaryDb() { ... }// 正确:指定事务管理器Bean名称
@Transactional("primaryTransactionManager")
public void updatePrimaryDb() { ... }

6.7 坑 7:异常被吞掉(最隐蔽的坑)

@Transactional
public void processOrder() {try {// 可能抛出异常的代码orderRepository.save(order);// 故意不处理异常} catch (Exception e) {// 仅打印日志,未重新抛出异常log.error("处理订单失败", e);}// 👉 事务不会回滚,因为异常没有传播出去
}// 修正:重新抛出异常或手动设置回滚
@Transactional
public void processOrder() {try {// ...} catch (Exception e) {log.error("处理订单失败", e);// 手动标记回滚(即使不抛异常)TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); }
}

6.8 坑 8:类未被 Spring 管理

// 错误:直接new对象,不受Spring事务管理
public class ManualService {@Autowiredprivate UserRepository userRepository;// 事务无效,因为该类未被@Service标记public void manualTransaction() {userRepository.save(new User());}
}// 正确:添加@Service注解
@Service
public class ManualService {// 事务生效
}

七、与 MyBatis/JPA 整合:具体场景的最佳实践

7.1 MyBatis 场景:批量操作的事务优化

@Service
public class BatchService {@Autowiredprivate UserMapper userMapper;// 错误:每次插入都开启新事务(性能差)public void batchInsertOld(List<User> users) {for (User user : users) {@Transactional // 注解在循环内,无效!userMapper.insert(user);}}// 正确:批量操作放在一个事务内@Transactionalpublic void batchInsertNew(List<User> users) {userMapper.batchInsert(users); // 一次性插入(需Mapper支持批量操作)}
}

7.2 JPA 场景:只读事务优化查询性能

@Service
public class QueryService {@Autowiredprivate UserRepository userRepository;// 标记为只读事务,数据库可优化锁机制@Transactional(readOnly = true) public List<User> getUsersByAge(int age) {return userRepository.findByAge(age);}
}

7.3 多数据源场景:指定事务管理器

@Service
public class MultiDbService {// 操作主库事务@Transactional("primaryTransactionManager") public void updatePrimaryDb() {primaryRepository.update(...);}// 操作从库事务@Transactional("secondaryTransactionManager") public void updateSecondaryDb() {secondaryRepository.update(...);}
}

八、分布式事务

8.1 什么是分布式事务?

当操作涉及多个数据库实例(如微服务架构中的订单库和库存库),传统本地事务失效,需要分布式事务解决方案。

8.2 三种主流方案对比

方案

核心原理

一致性

性能

适用场景

XA 协议

两阶段提交(2PC)

强一致

金融等高一致性场景

TCC 模式

Try-Confirm-Cancel 三阶段

最终一致

分布式电商、支付系统

Saga 模式

补偿事务(正向操作 + 反向补偿)

最终一致

长事务、柔性事务场景

8.3 Spring 集成 Seata(最简示例)

  1. 添加依赖:
    <dependency><groupId>io.seata</groupId><artifactId>seata-spring-boot-starter</artifactId><version>1.7.0</version>
    </dependency>
  2. 服务层添加全局事务注解:
    @GlobalTransactional // 分布式事务注解
    public void createOrder(Order order) {orderService.create(order);         // 订单库操作inventoryService.decreaseStock();  // 库存库操作
    }

九、事务调试与监控:必备的排查技巧

9.1 开启调试日志(关键!)

在application.properties中添加:

# 开启Spring事务调试日志
logging.level.org.springframework.transaction=DEBUG# 查看具体的SQL执行日志(MyBatis场景)
logging.level.com.example.mapper=DEBUG

9.2 常用排查命令

  1. 查看当前事务状态:
    TransactionStatus status = TransactionAspectSupport.currentTransactionStatus();
    boolean isNewTransaction = status.isNewTransaction(); // 是否新事务
    boolean isRollbackOnly = status.isRollbackOnly(); // 是否已标记回滚
  2. 查看事务管理器配置:
    @Autowired
    private PlatformTransactionManager transactionManager;// 输出事务管理器类型
    System.out.println(transactionManager.getClass().getName()); 

9.3 生产环境监控指标

建议监控以下指标(通过 Micrometer 或 Prometheus):

  • spring.transaction.active:当前活动事务数
  • spring.transaction.completed:已完成事务数(成功 + 失败)
  • transaction.rollback.rate:事务回滚率

十、总结

  1. 能用声明式就不用编程式:注解优先,减少代码复杂度
  2. 事务范围尽可能小
    1. 错误:在事务中包含网络调用、文件操作
    2. 正确:仅包裹必要的数据库操作
  3. 明确指定回滚异常
    @Transactional(rollbackFor = Exception.class) // 回滚所有异常

    ​​​​​​​

  4. 只读事务标记readOnly=true:提升数据库查询性能
  5. 设置合理的超时时间:避免长事务占用数据库连接
  6. 多数据源场景指定事务管理器:通过@Transactional("xxxTransactionManager")
  7. 内部方法调用使用代理对象:通过@Autowired注入自身解决事务失效
  8. 检查方法修饰符:必须是public方法才能被 AOP 代理
  9. 关闭 MyBatis 自动提交:确保 Spring 完全控制事务边界
  10. 开启调试日志:遇到事务问题先看日志,再断点调试
​​​​​​​​​​​​​​

只要按照这个指南一步步实践,即使是完全不懂事务的新手,也能在 Spring 开发中熟练运用事务,确保数据的一致性和完整性。记住:事务的核心是 "要么全做,要么全不做",所有的配置和代码都是为了实现这个目标。遇到问题不要慌,先看日志、再查注解参数、最后断点调试,99% 的问题都能解决!

相关文章:

  • ZYNQ学习记录FPGA(三)状态机
  • CBAM认证概述,CBAM认证的核心要素,CBAM认证的未来发展
  • 软件测试面试题总结【含答案】
  • 全球首个体重管理AI大模型“减单”发布,学AI大模型来近屿智能
  • 在Linux下使用vscode使用交叉编译工具链的gdb对core文件进行堆栈、变量查看
  • Spring Data MongoDB 技术指南
  • Spring核心框架完全指南 - 基础知识全解析
  • opencv vs2020正确的环境配置
  • Qt 动态插件系统QMetaObject::invokeMethod
  • 新闻类鸿蒙应用全链路运维指南:高并发场景下的稳定保障
  • Linux操作系统-性能优化
  • list类型
  • 亚远景-ASPICE在汽车软件全生命周期管理中的作用
  • AI Agent 的架构与技术体系分析
  • 在当系统未连接上wifi的时候,直接不显示wifi列表 ,这个判断导致?
  • 贪心选择 (Greedy Choice)
  • Vue2数组响应式问题:Object.defineProperty不能监听数组吗
  • 论文略读:RegMix: Data Mixture as Regression for Language Model Pre-training
  • 杉山将(Sugiyama Masa)《图解机器学习》
  • 2023蓝桥杯C/C++ B组国赛
  • 佛山网站设计电话/郑州搜索引擎优化公司
  • 威海网站建设兼职/花都网络推广seo公司
  • 怎么制作网站的网页设计/网站推广优化公司
  • 购物网站 开发/seo服务包括哪些
  • 做移动网站设计/公众号推广引流
  • 邯郸网站开发/百度指数代表什么意思