Spring事务失效的几种常见原因

  1. 数据库引擎不支持事务:如果您使用的数据库引擎不支持事务,那么您将无法使用Spring事务管理。

如使用mysql且引擎是MyISAM,则事务会不起作用,原因是MyISAM不支持事务,可以改成InnoDB引擎

  1. spring的事务注解@Transactional只能放在public修饰的方法上才起作用,如果放在其他非public(private,protected)方法上,虽然不报错,但是事务不起作用

说白了,在AbstractFallbackTransactionAttributeSource类的computeTransactionAttribute方法中有个判断,如果目标方法不是public,则TransactionAttribute返回null,即不支持事务。

  1. 异常未正确处理:
    这种情况下spring事务当然不会回滚,因为开发者自己捕获了异常,又没有手动抛出,换句话说就是把异常吞掉了。
    如果想要spring事务能够正常回滚,必须抛出它能够处理的异常。如果没有抛异常,则spring认为程序是正常的。
@Slf4j
@Service
public class UserService {
    
    
    @Transactional
    public void add(UserModel userModel) {
    
    
        try {
    
    
            saveData(userModel);
            updateData(userModel);
        } catch (Exception e) {
    
    
            log.error(e.getMessage(), e);
        }
    }
}

  1. 被final修饰的方法

final修饰的方法表明方法不能被子类重写
spring事务的底层是通过aop来创建一个代理类,而代理类无法重写该方法,无法实现事务功能。

注意:如果某个方法是static的,同样无法通过动态代理,变成事务方法。

@Service
public class UserService {
    
    

    @Transactional
    public final void add(UserModel userModel){
    
    
        saveData(userModel);
        updateData(userModel);
    }
}
  1. Spring配置错误,未被spring管理:如果您的Spring配置文件未正确配置,例如未启用事务管理器或未正确配置数据源,则可能导致事务失效。

在我们平时开发过程中,有个细节很容易被忽略。即使用spring事务的前提是:对象要被spring管理,需要创建bean实例。

通常情况下,我们通过@Controller、@Service、@Component、@Repository等注解,可以自动实现bean实例化和依赖注入的功能。

如果有一天,你匆匆忙忙的开发了一个Service类,但忘了加@Service注解,比如:

//@Service
public class UserService {
    
    
    @Transactional
    public void add(UserModel userModel) {
    
    
         saveData(userModel);
         updateData(userModel);
    }    
}

从上面的例子,我们可以看到UserService类没有加@Service注解,那么该类不会交给spring管理,所以它的add方法也不会生成事务。

  1. 方法内部调用
@Service
public class ServiceImpl implements Service {
    
    
    public void test(string xxxx) {
    
    
        update(xxxx);
    }
    
    @Transactional(propagation =  Propagation.REQUIRED)
    public void update(string xxxx) {
    
    
            // update logic
    }
}

因为是AOP,直接调用内部方法并非是代理类调用。处理方式详情可见:Service事务优化(方法能否被事务控制?)
可能有些人可能会有这样的疑问:这种做法会不会出现循环依赖问题?
答案:不会。其实spring Ioc内部的三级缓存保证了它,不会出现循环依赖问题。

猜你喜欢

转载自blog.csdn.net/weixin_54514751/article/details/130982594