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