java中事务失效的几种原因 - 面试宝典

举报
皮牙子抓饭 发表于 2023/08/06 13:50:09 2023/08/06
【摘要】 在Java中,事务失效的几种常见原因有:缺少@Transactional注解:在使用Spring框架进行事务管理时,需要对需要事务控制的方法或类添加@Transactional注解。如果忘记添加该注解,事务将无法生效。事务方法内部捕获异常:如果事务方法内部捕获了异常并且没有抛出或回滚事务,则事务将会失效。事务的生效需要异常被抛出到事务边界,由事务管理器进行事务的回滚。异常被try-catch...

在Java中,事务失效的几种常见原因有:

  1. 缺少@Transactional注解:在使用Spring框架进行事务管理时,需要对需要事务控制的方法或类添加@Transactional注解。如果忘记添加该注解,事务将无法生效。
  2. 事务方法内部捕获异常:如果事务方法内部捕获了异常并且没有抛出或回滚事务,则事务将会失效。事务的生效需要异常被抛出到事务边界,由事务管理器进行事务的回滚。
  3. 异常被try-catch块吞掉:如果在事务方法内部使用了try-catch块,并且没有抛出或回滚事务,事务将会失效。为了保证事务的生效,需要在catch块中抛出异常或者手动回滚事务。
  4. 方法未被代理:Spring的事务管理是通过代理模式实现的,只有通过代理调用的方法才会被事务管理器拦截并启动事务。如果直接在该类的实例上调用方法,事务将不会生效。
  5. 方法为private或final:Spring的事务管理是通过动态代理实现的,只能代理非final的public方法。如果事务方法被声明为private或final,事务将不会生效。
  6. 外部调用事务方法:如果在同一个类中的一个事务方法内部调用另一个事务方法,外部事务将会失效。这是因为Spring默认使用基于代理的事务拦截器,而代理只能拦截外部调用的方法。 要解决事务失效的问题,可以检查以上几个方面,确保事务方法上添加了@Transactional注解,异常被正确抛出或回滚事务,方法被代理调用,以及避免在同一个类中的事务方法相互调用。

以下是一个简单的示例代码,展示了事务失效的几种情况:

javaCopy code@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
    @Transactional
    public void createUser(String username, String password) {
        try {
            User user = new User(username, password);
            userRepository.save(user);
            throw new RuntimeException("Something went wrong"); // 抛出异常
        } catch (Exception e) {
            // 异常被捕获,但没有抛出或回滚事务
            e.printStackTrace();
        }
    }
    @Transactional
    public void updateUser(String username, String newPassword) {
        User user = userRepository.findByUsername(username);
        user.setPassword(newPassword);
        // 没有抛出异常或回滚事务,事务将会失效
    }
    @Transactional
    public void callInternalTransactionMethod() {
        // 外部事务内部调用另一个事务方法,外部事务将会失效
        createUser("Alice", "123456");
    }
    public void directMethodCall() {
        // 直接调用方法,事务将不会生效
        updateUser("Alice", "newPassword");
    }
}

在上述示例中,​​createUser​​方法中抛出了异常,但异常被捕获后没有抛出或回滚事务,导致事务失效。​​updateUser​​方法没有抛出异常或回滚事务,也导致事务失效。​​callInternalTransactionMethod​​方法在外部事务内部调用了另一个事务方法,导致外部事务失效。​​directMethodCall​​方法直接调用了事务方法,事务将不会生效。 为了解决这些问题,可以在​​createUser​​方法中添加​​throw e​​语句来抛出异常,或者使用​​TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()​​手动回滚事务。在​​updateUser​​方法中,可以添加​​throw new RuntimeException("Something went wrong")​​语句来抛出异常,或者使用​​TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()​​手动回滚事务。在​​callInternalTransactionMethod​​方法中,应该将调用​​createUser​​方法的逻辑提取到另一个类中,并通过依赖注入的方式调用该类的方法,以确保事务生效。在使用​​directMethodCall​​方法时,应该通过依赖注入方式调用事务方法,而不是直接调用。这样可以确保事务生效。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。