这个问题是 Spring 面试高频题,面试官通常希望你不仅知道场景,还知道为什么失效(AOP代理机制)。
核心原因
Spring 事务本质上是:
@Transactional ↓ AOP代理 ↓ TransactionInterceptor ↓ 开启事务 ↓ 执行方法 ↓ 提交/回滚如果没有经过 Spring 代理对象:
事务不会生效1. 方法不是 public
错误写法:
@Service public class UserService { @Transactional private void saveUser() { } }失效原因:
Spring AOP 默认只代理:
public 方法正确:
@Transactional public void saveUser() { }2. 自调用(最经典)
@Service public class UserService { public void test() { saveUser(); } @Transactional public void saveUser() { } }调用过程
this.saveUser()而不是:
代理对象.saveUser()绕过AOP。
事务失效。
面试官最爱问:
A(){ B(); } @Transactional B()为什么事务不生效?
答案:
同类内部调用 没有经过代理对象解决:
@Autowired private UserService userService; userService.saveUser();或者:
AopContext.currentProxy()3. final 方法
@Transactional public final void saveUser() { }如果是 CGLIB:
原理:
生成子类 重写方法 增强事务但是:
final不能重写。
因此:
事务失效4. static 方法
@Transactional public static void saveUser() { }静态方法属于类:
Class不属于对象。
代理无法拦截。
事务失效。
5. 捕获异常未抛出
错误:
@Transactional public void save() { try { int a = 1 / 0; } catch (Exception e) { } }Spring判断:
方法正常结束于是:
提交事务不会回滚。
正确:
catch (Exception e){ throw e; }或者:
TransactionAspectSupport .currentTransactionStatus() .setRollbackOnly();6. 抛出检查异常
Spring默认:
RuntimeException Error才回滚。
例如:
@Transactional public void save() throws Exception { throw new Exception(); }默认:
不会回滚解决:
@Transactional( rollbackFor = Exception.class )7. 数据库引擎不支持事务
例如:
MyISAM即使:
@Transactional也没用。
因为:
数据库本身不支持事务查看:
show table status;应该:
InnoDB8. 未被Spring管理
错误:
UserService service = new UserService();此时:
自己new出来不是IOC容器Bean。
没有代理。
事务失效。
正确:
@Autowired UserService service;9. 多线程导致事务失效
@Transactional public void save() { executor.submit(() -> { userMapper.insert(); }); }事务绑定:
ThreadLocal主线程:
有事务子线程:
没有事务因此:
事务无法传递10. 方法所在类没有被扫描
例如:
@Service没加。
或者:
@ComponentScan未扫描到。
Spring根本没创建Bean。
事务失效。
11. propagation 配置错误
例如:
@Transactional( propagation = NOT_SUPPORTED )含义:
挂起当前事务或者:
PROPAGATION_NEVER要求:
不能存在事务配置不当容易造成:
事务没有按预期生效12. @Transactional加在接口上
public interface UserService { @Transactional void save(); }JDK动态代理:
可能生效CGLIB:
可能失效最佳实践:
写实现类@Service public class UserServiceImpl总结
Spring事务底层基于AOP代理实现,本质是通过 TransactionInterceptor 在方法执行前开启事务、执行后提交事务、出现异常时回滚事务。因此凡是没有经过代理对象调用的场景都会导致事务失效。
常见失效场景包括:
- 方法不是 public;
- 同类内部自调用;
- final 方法;
- static 方法;
- 自己 new 对象而非 Spring Bean;
- 捕获异常未继续抛出;
- 抛出 Checked Exception 未配置 rollbackFor;
- 数据库不支持事务;
- 多线程导致事务无法通过 ThreadLocal 传播;
- Bean 未被 Spring 容器管理;
- propagation 配置不当。