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

在Java中,事务失效的几种常见原因有:
- 缺少@Transactional注解:在使用Spring框架进行事务管理时,需要对需要事务控制的方法或类添加@Transactional注解。如果忘记添加该注解,事务将无法生效。
- 事务方法内部捕获异常:如果事务方法内部捕获了异常并且没有抛出或回滚事务,则事务将会失效。事务的生效需要异常被抛出到事务边界,由事务管理器进行事务的回滚。
- 异常被try-catch块吞掉:如果在事务方法内部使用了try-catch块,并且没有抛出或回滚事务,事务将会失效。为了保证事务的生效,需要在catch块中抛出异常或者手动回滚事务。
- 方法未被代理:Spring的事务管理是通过代理模式实现的,只有通过代理调用的方法才会被事务管理器拦截并启动事务。如果直接在该类的实例上调用方法,事务将不会生效。
- 方法为private或final:Spring的事务管理是通过动态代理实现的,只能代理非final的public方法。如果事务方法被声明为private或final,事务将不会生效。
- 外部调用事务方法:如果在同一个类中的一个事务方法内部调用另一个事务方法,外部事务将会失效。这是因为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方法时,应该通过依赖注入方式调用事务方法,而不是直接调用。这样可以确保事务生效。
- 点赞
- 收藏
- 关注作者
 
             
           
评论(0)