
Spring 事务的失效原因有什么?
前言
“面试造火箭,入职拧螺丝?” 别慌!这里没有“茴香豆的茴有几种写法”,只有最实用、最高频、最能唬住面试官的 Java 面试题解析!
正文
每日一题:Spring 事务的失效原因有什么?
难度系数: ⭐⭐
用 Spring 的 @Transactional 注解控制事务有哪些不生效的场景:
一、 数据库引擎不支持事务
这里以 MySQL 为例,其 MyISAM 引擎是不支持事务操作的,InnoDB 才是支持事务的引擎,一般要支持事务都会使用 InnoDB。
二、没有被 Spring 管理
// @ServicepublicclassUserServiceImplimplementsUserService{ @Transactional publicvoidupdate(User user) { // 此处省略三个字... }}如果此时把 @Service 注解注释掉,这个类就不会被加载成一个 Bean,那这个类就不会被 Spring 管理了,事务自然就失效了。
三、方法不是 public 的
以下内容来自 Spring 官方文档👇
When using proxies, you should apply the @Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. Consider the use of AspectJ (see below) if you need to annotate non-public methods.
大概意思就是 @Transactional 只能用于public的方法上,否则事务不会失效,如果要用在非 public 方法上,可以开启 AspectJ 代理模式。
四、自身调用问题
本类中A方法调用本类中B方法时,事务不生效👇
@ServicepublicclassUserServiceImplimplementsUserService{
publicvoidupdate(User user) { updateUser(user); }
@Transactional publicvoidupdateUser(User user) { // 此处省略三个字... }}因为它们发生了自身调用,也就是某个类调用自己的方法,而没有经过 Spring 的代理类,此时事务也会失效,默认只有在外部调用事务才会生效。这个的解决方案之一就是在的类中注入自己,用注入的对象再调用另外一个方法。当然了,这个不太优雅, 还一个办法是通过 AopContext.currentProxy () 获取到本类的代理对象再进行调用。
五、@Transactional 的扩展配置 propagation 是否正确
@ServicepublicclassUserServiceImplimplementsUserService{
@Transactional publicvoidupdate(User user) { updateUser(User); }
@Transactional(propagation = Propagation.NOT_SUPPORTED) publicvoidupdateUser(User user) { // 此处省略三个字... }
}Propagation.NOT_SUPPORTED 表示不以事务运行,当前若存在事务则挂起,此时就是因为 propagation 配置不正确导致事务不生效。
六、异常被吃了
@ServicepublicclassUserServiceImplimplementsUserService{
@Transactional publicvoidupdateUser(User user) { try { // 此处省略三个字... } catch {
} }}此时把异常吃了,然后又不抛出来,事务依然不会回滚。
七、异常类型错误
我们修改一下上面的例子,如下所示👇
@ServicepublicclassUserServiceImplimplementsUserService{
@Transactional publicvoidupdateUser(User user) { try { // 此处省略三个字... } catch {thrownewException("错误"); } }}这样事务也是不生效的,因为默认回滚的是 RuntimeException,如果你想触发其他异常的回滚,需要在注解上配置一下,如:
@Transactional(rollbackFor = Exception.class)小结
4
📢 面试不是终点,而是技术成长的起点!持续关注本专栏,更多硬核内容在路上!
如果觉得有用,别忘了点赞+关注,你的支持是我更新的最大动力❤️
END