无标题
Spring显示声明事务失效
Spring事务原理
Spring 事务的实现基于AOP(面向切面编程) 和事务管理器(TransactionManager),核心是通过代理机制对目标方法进行环绕增强,在方法执行前后嵌入事务的开启、提交、回滚等逻辑
- 当调用被@Transactional注解标记的方法时,实际执行的是代理对象的方法。
- 代理对象会先触发事务拦截器(TransactionInterceptor),由拦截器完成事务的开启、提交或回滚。
- 事务拦截器的逻辑由事务管理器(TransactionManager) 实现,不同的数据源(如 JDBC、Hibernate、MyBatis)对应不同的事务管理器。
Spring事务失效场景
1.自调用
事务通过代理对象触发,同一类内方法调用时使用this,未经过代理,导致事务逻辑不生效。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class UserServiceImpl implements UserService {
public void transfer(User user) {
// this.doSomething(fromId, toId, amount);
doSomething(user);
// UserService proxy = (UserService) AopContext.currentProxy();
// proxy.doSomething(user);
}
public void doSomething(User user) {
userMapper.insert(user);
}
}
2.非 public方法使用 @Transactional
Spring 的事务管理基于 AOP 动态代理实现,而默认的代理逻辑(如SpringAopProxy)仅对public方法进行事务增强。这是因为 Java 语言规范中,非 public 方法的可见性限制导致代理无法有效拦截,最终事务注解被忽略。
Spring 约定1
2
3
4
5
6
7
8
public class UserServiceImpl implements UserService {
private void test(User user) {
userMapper.insert(user);
}
}
3.异常被捕获且未重新抛出
Spring 事务默认通过未捕获的异常触发回滚触发,若异常被 try-catch 捕获且未抛出,事务管理器认为执行成功,不会回滚。1
2
3
4
5
6
7
8
9
10
11
12
13
public class UserServiceImpl implements UserService {
public void test(User user) {
try {
userMapper.insert(user);
} catch (Exception e) {
// 捕获异常但未抛出,事务管理器感知不到
System.out.println("发生异常:" + e.getMessage());
}
}
}
4.异常类型不匹配导致事务失效
默认仅对 RuntimeException 和 Error 回滚,若抛出Checked Exception(如 IOException)且未通过 rollbackFor 指定,事务不回滚。1
2
3
4
5
6
7
8
9
10
public class UserServiceImpl implements UserService {
// 默认只回滚 RuntimeException,此处抛出受检异常
public void test(User user) throws IOException {
userMapper.insert(user);
// 抛出受检异常(IOException),默认不回滚
throw new IOException("模拟受检异常");
}
}
5.目标类未被 Spring 管理
事务依赖 Spring 容器生成的代理对象,若通过 new 手动创建对象,无代理增强,注解失效。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class UserServiceImpl implements UserService {
public void test(User user) {
userMapper.insert(user);
}
}
public class TestController {
public String test(User user) {
UserService userService = new UserService();
userService.test(user);
}
}
小结
Spring 事务失效的本质是 调用路径没有经过事务代理。理解 AOP 代理机制是解决所有事务失效问题的关键。在实际开发中,同类自调用和异常被捕获是最容易踩坑的两个场景。



