Skip to content

<tx:advice/> 设置 ​

本节总结了通过使用 <tx:advice/> 标签可以指定的各种事务设置。默认的 <tx:advice/> 设置如下:

  • 事务传播设置 为 REQUIRED。
  • 隔离级别为 DEFAULT。
  • 事务是读写的。
  • 事务超时默认为底层事务系统的默认超时,如果不支持超时,则没有超时。
  • 任何 RuntimeException 都会触发回滚,而任何检查型 Exception 则不会。

你可以更改这些默认设置。下表总结了嵌套在 <tx:advice/> 和 <tx:attributes/> 标签内的 <tx:method/> 标签的各种属性:

属性是否必须默认值描述
name是与事务属性关联的方法名称。可以使用通配符 (*) 字符将相同的事务属性设置与多个方法关联(例如,get*、handle*、on*Event 等)。
propagation否REQUIRED事务传播行为。
isolation否DEFAULT事务隔离级别。仅适用于传播设置为 REQUIRED 或 REQUIRES_NEW 的情况。
timeout否-1事务超时(秒)。仅适用于传播设置为 REQUIRED 或 REQUIRES_NEW 的情况。
read-only否false读写事务与只读事务。仅适用于 REQUIRED 或 REQUIRES_NEW。
rollback-for否触发回滚的 Exception 实例的逗号分隔列表。例如,com.foo.MyBusinessException,ServletException。
no-rollback-for否不触发回滚的 Exception 实例的逗号分隔列表。例如,com.foo.MyBusinessException,ServletException。

补充教学 ​

1. 为什么 Isolation 和 Timeout 只有在 REQUIRED/REQUIRES_NEW 时才生效? ​

这是一个非常重要的潜在“坑”。

  • SUPPORTS: 如果当前有事务,就用当前的;如果没有,就非事务执行。
    • 如果是非事务执行,当然没有隔离级别和超时一说。
    • 如果是加入现有事务,那么隔离级别和超时完全取决于发起该事务的方法,你无权更改。
  • MANDATORY: 必须加入现有事务。同理,你只能听命于人,无法自己设定隔离级别。
  • REQUIRED:
    • 如果新建事务:你设置的隔离级别和超时生效。
    • 如果加入事务:你设置的隔离级别会被忽略(因为事务已经开启了,隔离级别不能中途变),但有些事务管理器(如 JpaTransactionManager)可能会校验你的设置是否与现有事务冲突。

2. 隔离级别 DEFAULT 到底是什么? ​

isolation="DEFAULT" 表示使用底层数据库的默认隔离级别。

  • MySQL (InnoDB): 可重复读 (REPEATABLE READ)。
  • Oracle / SQL Server / PostgreSQL: 读已提交 (READ COMMITTED)。 核心提示:如果你的代码对“不可重复读”或“幻读”敏感,千万不要依赖 DEFAULT,而应该显式指定(如 isolation="REPEATABLE_READ"),以确保跨数据库迁移时的行为一致性。

3. timeout 的单位与精度 ​

  • timeout 属性的单位是秒。
  • 它指的是事务总执行时间。Spring 会在拿到数据库连接后设置此超时。如果业务逻辑执行非常慢(比如调用了外部 API),当在超时后执行下一条 SQL 时,数据库驱动或 Spring 可能会抛出 TransactionTimedOutException。

4. 关于 read-only 的补充说明 ​

在 <tx:method read-only="true"/> 中,read-only 只是给事务管理器的一个“提示”(Hint)。

  • 有效场景:对于 Hibernate/JPA,它能显著优化性能(禁止脏检查)。
  • 无效场景:并非所有数据库驱动都百分百遵守这个只读标记。
  • 误区:它不能完全防止你代码里的写入操作。如果你在只读事务里硬要写数据,某些数据库配置下会报错,而某些情况下可能依然能写进去(取决于具体驱动实现),所以不要把它当作安全特性,而应视作性能优化特性。

Based on Spring Framework.