对线面试官:列出 @Transactional 注解下,事务失效的七种场景

@Transactional是一种基于注解管理事务的方式,Spring通过动态代理的方式为目标方法实现事务管理的增强。

@Transactional使用起来方便,但也需要注意引起@Transactional失效的场景,本文总结了七种情况,下面进行逐一分析。

1、异常被捕获后没有抛出

当异常被捕获后,并且没有再抛出,那么deleteUserA是不会回滚的。

@Transactional
public void deleteUser() {
    userMapper.deleteUserA();
    try {
        int i = 1 / 0;
        userMapper.deleteUserB();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

2、抛出非运行时异常

异步虽然抛出了,但是抛出的是非RuntimeException类型的异常,依旧不会生效。

@Transactional
public void deleteUser() throws MyException{
    userMapper.deleteUserA();
    try {
        int i = 1 / 0;
        userMapper.deleteUserB();
    } catch (Exception e) {
        throw new MyException();
    }
}

如果指定了回滚异常类型为Exception,那么就可以回滚非RuntimeException类型异常了。

@Transactional(rollbackFor = Exception.class)

3、方法内部直接调用

如果先调用deleteUser(),那么deleteUserA()是不会回滚的,其原因就是@Transactional根本没生成代理,如果直接调用deleteUser2()那么没问题,deleteUserA()会回滚。

public void deleteUser() throws MyException{
    deleteUser2();
}

@Transactional
public void deleteUser2() throws MyException{
    userMapper.deleteUserA();
    int i = 1 / 0;
    userMapper.deleteUserB();
}

修改方式,把当前类自己注入一下调用即可。

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
 //自己注入自己
    @Autowired
    UserService userService;

 public void deleteUser() throws MyException{
     userService.deleteUser2();
 }

 @Transactional
 public void deleteUser2() throws MyException{
     userMapper.deleteUserA();
     int i = 1 / 0;
     userMapper.deleteUserB();
 }
}

4、新开启一个线程

如下的方式deleteUserA()也不会回滚,因为spring实现事务的原理是通过ThreadLocal把数据库连接绑定到当前线程中,新开启一个线程获取到的连接就不是同一个了。

@Transactional
public void deleteUser() throws MyException{
    userMapper.deleteUserA();
 try {
  //休眠1秒,保证deleteUserA先执行
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    new Thread(() -> {
        int i = 1/0;
        userMapper.deleteUserB();
    }).start();    
}

5、注解到private方法上

IDEA直接会给出提示Methods annotated with ‘@Transactional’ must be overridable ,原理很简单,private修饰的方式,spring无法生成动态代理。

@Transactional
private void deleteUser() throws MyException{
    userMapper.deleteUserA();
    int i = 1/0;
    userMapper.deleteUserB();
}

6、数据库本身不支持

MySQL数据库,必须设置数据库引擎为InnoDB。

7、事务传播属性设置错误

注意传播属性的设置,比如设置了:PROPAGATION_NOT_SUPPORIED(以非事务的方式执行,如果当前有事务则把当前事务挂起)。

来源|blog.csdn.net/CSDN_WYL2016/article/details/106767583

后端专属技术群

构建高质量的技术交流社群,欢迎从事编程开发、技术招聘HR进群,也欢迎大家分享自己公司的内推信息,相互帮助,一起进步!

文明发言,以交流技术职位内推行业探讨为主

广告人士勿入,切勿轻信私聊,防止被骗

对线面试官:列出 @Transactional 注解下,事务失效的七种场景

加我好友,拉你进群

原文始发于微信公众号(Java知音):对线面试官:列出 @Transactional 注解下,事务失效的七种场景

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/155883.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!