Skip to content

<tx:advice/> 设置

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

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

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

属性是否必须默认值描述
name与事务属性关联的方法名称。可以使用通配符 (*) 字符将相同的事务属性设置与多个方法关联(例如,get*handle*on*Event 等)。
propagationREQUIRED事务传播行为。
isolationDEFAULT事务隔离级别。仅适用于传播设置为 REQUIREDREQUIRES_NEW 的情况。
timeout-1事务超时(秒)。仅适用于传播设置为 REQUIREDREQUIRES_NEW 的情况。
read-onlyfalse读写事务与只读事务。仅适用于 REQUIREDREQUIRES_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.