1. 同类内部方法调用(最常见)
场景
java
@Service
public class UserService {
// 没有 @Transactional
public void saveUser() {
// 同类内部直接调用 → 不经过代理 → 事务失效
doSave();
}
@Transactional
public void doSave() {
// 增删改操作
}
}
原因
- Spring 事务基于 AOP 动态代理
- 同类内部
this.方法()调用,不走代理对象 → 切面不生效
解决方案
-
注入自身 Bean
java@Autowired private UserService userService; public void saveUser() { userService.doSave(); // 走代理 } -
使用 AopContext.currentProxy()
-
把方法拆到不同类
2. 方法不是 public(private/protected/default)
场景
java
@Transactional
private void update() {
// 事务不生效
}
原因
- Spring AOP 代理只支持 public 方法
- 非 public 方法会被直接跳过事务切面
解决方案
- 改成 public
3. @Transactional 加在了接口上,类没被 Spring 管理
场景
java
public interface UserService {
@Transactional
void add();
}
// 没加 @Service、@Component
public class UserServiceImpl implements UserService {}
原因
- 没被 Spring 管理 → 不生成代理 → 事务无效
解决方案
- 类上加
@Service
4. 异常被 try-catch 吃掉,没抛出去
场景
java
@Transactional
public void save() {
try {
// 数据库操作
} catch (Exception e) {
// 只打印日志,不抛异常
log.error("...");
}
}
原因
- Spring 默认只对 RuntimeException & Error 回滚
- 异常被捕获 → 事务感知不到 → 不会回滚
解决方案
-
catch 后重新抛出
javacatch (Exception e) { throw new RuntimeException(e); } -
注解指定回滚异常
java@Transactional(rollbackFor = Exception.class)
5. 抛出了非 RuntimeException(受检异常)
场景
java
@Transactional
public void test() throws Exception {
// 抛出 Exception / IOException 等
}
原因
- 默认只回滚
RuntimeException和Error Exception这种受检异常 不触发回滚
解决方案
java
@Transactional(rollbackFor = Exception.class)
6. 多线程调用,事务不共享
场景
java
@Transactional
public void save() {
new Thread(() -> {
// 子线程里的数据库操作
}).start();
}
原因
- Spring 事务基于 ThreadLocal
- 子线程和主线程不是同一个线程 → 独立连接,独立事务
解决方案
- 子线程方法自己加
@Transactional - 不用异步,或用 CountDownLatch 同步控制
7. 使用了错误的传播机制(NOT_SUPPORTED/NEVER)
场景
java
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void update() {
// 以非事务方式执行
}
原因
NOT_SUPPORTED:挂起事务,非事务执行NEVER:强制非事务,有事务直接抛异常
解决方案
- 使用默认
REQUIRED
8. 数据库引擎不支持事务(MyISAM)
场景
建表时用了 MyISAM
sql
CREATE TABLE t(...) ENGINE=MyISAM;
原因
- MyISAM 不支持事务
- 代码怎么写都不会回滚
解决方案
- 改成 InnoDB
一张表速记
| 场景 | 失效原因 | 一句话解决 |
|---|---|---|
| 同类内部调用 | 不走代理 | 注入自身调用 |
| 非 public | AOP不代理 | 改成public |
| 异常被catch | 没抛出去 | 重新抛出 |
| 抛受检异常 | 默认不回滚 | rollbackFor=Exception |
| 多线程 | ThreadLocal不共享 | 子线程独立事务 |
| 传播机制错 | 禁用事务 | 用REQUIRED |
| 没被Spring管理 | 无代理 | 加@Service |
| MyISAM | 引擎不支持 | 换InnoDB |