SpringBoot事物失效场景

在使用SpringBoot的开发过程中,我们有时候会遇到明明加了事务但是却不生效的场景,今天就稍微整理一下。


场景一:方法未被声明为事务

在Spring Boot中,事务是基于注解或XML配置的方式进行声明的。如果一个方法没有被声明为事务,那么其中的数据库操作将不会受到事务管理的影响,可能导致数据不一致的问题。

public class UserService {
    private final UserRepository userRepository;
 
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
 
    // 事务未声明
    public void updateUserStatus(Long userId, boolean active) {
        userRepository.updateStatus(userId, active);
    }
}


在上述示例中,updateUserStatus方法没有被声明为事务,即使该方法中的数据库更新操作失败,也不会回滚,可能导致数据库中的数据和应用状态不一致。


场景二:异常未被抛出

在默认情况下,Spring事务管理器只会在方法抛出RuntimeException及其子类的异常时回滚事务。如果方法抛出的是受检查异常或未抛出任何异常,事务将不会回滚。

@Service
@Transactional
public class OrderService {
    private final OrderRepository orderRepository;
 
    public OrderService(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }
 
    public void placeOrder(Order order) throws IOException {
        // 数据库更新操作
        orderRepository.save(order);
 
        // 受检查异常未被抛出
        try {
            sendNotification(order);
        } catch (IOException e) {
            // 异常被捕获,事务不会回滚
        }
    }
 
    private void sendNotification(Order order) throws IOException {
        // 发送通知
        throw new IOException("Failed to send notification");
    }
}


在上述示例中,placeOrder方法中的数据库更新操作将会执行,即使在sendNotification方法中抛出了异常。因为sendNotification方法中的异常被捕获了,并未向上抛出。


场景三:方法不是公开的

在Spring事务管理中,默认情况下只会应用于公开方法。如果事务注解所标注的方法是私有、受保护或默认访问级别的,事务将无效。
 

@Service
public class UserService {
    private final UserRepository userRepository;
 
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
 
    // 私有方法,事务不会应用于该方法
    @Transactional
    private void updateUserStatus(Long userId, boolean active) {
        userRepository.updateStatus(userId, active);
    }
 
    public void activateUser(Long userId) {
        updateUserStatus(userId, true);
    }
}

 在上述示例中,updateUserStatus方法是私有的,虽然在activateUser方法中调用了它,但事务注解将不会应用于私有方法,导致事务失效。

总结

总结一些场景可能导致事务失效,例如:

  1. 未捕获的异常:如果在事务内部发生了未捕获的异常,并且该异常没有被处理或抛出到事务管理器,事务将会失效。

  2. 未使用@Transactional注解:在Spring Boot中,使用@Transactional注解来标记方法或类的事务边界。如果未使用该注解或使用错误的方式,事务将不会生效。

  3. 异步方法调用:如果在一个事务方法中调用了一个使用异步机制的方法(如使用@Async注解标记的方法),事务可能会失效,因为事务可能在异步方法执行之前就已经提交或回滚。

  4. 同一个类中的方法调用:如果在同一个类中的两个方法之间进行调用,并且这两个方法都有事务注解,事务可能会失效。这是因为Spring AOP默认是通过代理对象实现事务的,而同一个类中的方法调用不会触发代理。

代码示例:

@Service
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    @Transactional
    public void createUser(User user) {
        userRepository.save(user);
        throw new RuntimeException("Oops! Something went wrong."); // 未捕获的异常导致事务失效
    }
    
    public void updateUser(User user) {
        updateUserEmail(user); // 在同一个类中的方法调用,事务可能会失效
    }
    
    @Transactional
    public void updateUserEmail(User user) {
        userRepository.save(user);
        someAsyncMethod(); // 异步方法调用,事务可能会失效
    }
    
    @Async
    public void someAsyncMethod() {
        // 异步操作
    }
}


这些是一些可能导致Spring Boot事务失效的常见场景和示例。在实际开发中,应注意事务的声明、异常的抛出和方法的可见性,以确保事务的正确应用和回滚。

为了解决这些问题,可以采取以下措施:

  1. 确保在事务方法中捕获并处理所有的异常,或者让异常传播到事务管理器。

  2. 使用正确的方式添加@Transactional注解,确保事务生效。

  3. 避免在事务方法中调用异步方法,或者通过其他方式确保异步方法执行完毕后再提交事务。

  4. 在同一个类中的方法调用时,通过从容器中获取代理对象而不是直接调用方法,以确保事务生效。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

枫飞雪飘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值