@Transactional生效需满足代理调用、public方法、非自调用等前提;传播行为按业务选(如REQUIRES_NEW用于独立日志),readOnly优化查询,rollbackFor需显式指定受检异常。

Java 事务硬核通关,关键不在堆砌配置,而在理清“什么时候用什么方式、为什么这么配”。配置只是手段,背后的事务边界、传播行为、隔离级别和回滚策略才是核心。下面从实战角度拆解最关键的三类配置场景。
Spring 声明式事务:@Transactional 的正确打开方式
这是最常用也最容易配错的方式。重点不是加注解,而是理解它生效的前提和限制:
- 必须走 Spring 代理:非 public 方法、同类内自调用(this.method())、未启用 AOP 或 proxy-target-class 配置错误,都会导致 @Transactional 失效
- 传播行为要按业务选:默认 REQUIRED 已覆盖多数场景;但嵌套下单扣库存+发消息,若消息服务失败不希望回滚库存,就得用 REQUIRES_NEW;只读操作建议配 readOnly = true,让数据库优化执行计划
- 回滚规则别依赖默认:默认只对 RuntimeException 和 Error 回滚。若业务异常是受检异常(如 BusinessException),需显式声明 rollbackFor = BusinessException.class
JPA/Hibernate 事务与 EntityManager 的联动
用 JPA 时,事务配置不能脱离 EntityManager 生命周期。常见误区是只配了 @Transactional,却忽略 persistence.xml 或 Spring Boot 中的 flush 模式:
- flush-before-commit 是默认行为,但若手动调用 entityManager.flush() 后再抛异常,可能提前触发 SQL 执行,导致部分写入无法回滚
- 避免在事务外访问延迟加载属性:@Transactional 缺失或范围过小,会导致 LazyInitializationException —— 这不是配置问题,而是事务边界没包住数据消费点
- 慎用 setFlushMode(FlushModeType.COMMIT):它会推迟所有变更到提交时刻,看似安全,但掩盖了脏读、序列化失败等真实问题
编程式事务:PlatformTransactionManager + TransactionTemplate 的精准控制
当声明式粒度不够(比如一个方法里只想对某几行代码加事务),就得上编程式。但不是随便 new 个 TransactionTemplate 就行:
立即学习“Java免费学习笔记(深入)”;
- TransactionTemplate 默认使用当前线程绑定的事务:若已在外部事务中,它会沿用而非新建——想强制独立事务,得配 PROPAGATION_REQUIRES_NEW
- 不要混用两种编程式写法:PlatformTransactionManager 手动 commit/rollback 容易漏异常处理;TransactionTemplate.execute 更安全,推荐用有返回值的 TransactionCallback<T>
- 事务属性要显式传入:比如 new DefaultTransactionDefinition().setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED),不能依赖框架默认,尤其跨库或高并发场景
配事务不是填参数游戏。真正硬核的是:看到一段扣余额代码,能立刻判断它该不该在事务里、该用什么传播行为、隔离级别是否足够防超卖、回滚是否覆盖所有异常路径。配置只是把这种判断落地的工具。


















