spring事物失效的原因

本文详细探讨了Spring事务失效的常见原因,包括数据库引擎限制、方法访问权限、未被Spring管理的bean、事务传播行为等,并解析了声明式事务的实现原理。此外,还提供了如何通过正确配置传播行为和处理异常来避免事务失效的建议。
摘要由CSDN通过智能技术生成

1 spring事物实现方式及原理

Spring 事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring 是无法提供事务功能的。真正的数据库层的事务提交和回滚是通过binlog 或者 redo log 实现的。

一般我们在程序里面使用的都是在方法上面加@Transactional 注解,这种属于声明式事物。

声明式事务本质是通过 AOP 功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

2 失效原因

1.1 数据库本身不支持事物

这里以 MySQL 为例,其 MyISAM 引擎是不支持事务操作的,InnoDB 才是支持事务的引擎,一般要支持事务都会使用 InnoDB。

2.2 方法不是public的

注解@Transactional只能放在public修饰的方法上才起作用(private 方法是不会被spring代理的,因此是不会有事物产生的,这种做法是无效的)。

2.3 没有被 Spring 管理

没有被spring管理的bean, spring连代理对象都无法生成,事务自然无效。

2.4 当前类的调用

@Service
public class UserServiceImpl implements UserService {

    public void update(User user) {
        updateUser(user);
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateUser(User user) {
        // update user
    }

}

上面的这种情况下是不会有事物管理操作的。

通过看声明式事物的原理可知,spring使用的是AOP切面的方式,本质上使用的是动态代理来达到事物管理的目的,当前类调用的方法上面加@Transactional 这个是没有任何作用的,因为调用这个方法的是this。

我们再看下面的一种例子:

@Service
public class UserServiceImpl implements UserService {

    @Transactional(rollbackFor = Exception.class)
    public void update(User user) {
        updateUser(user);
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void updateUser(User user) {
        // update user
    }

}

这次在 update 方法上加了 @Transactional,updateUser 加了 REQUIRES_NEW 新开启一个事务,那么新开的事务管用么?

答案是:不管用!

因为它们发生了自身调用,就调该类自己的方法,而没有经过 Spring 的代理类,默认只有在外部调用事务才会生效,这也是老生常谈的经典问题了。

2.5 配置的事物传播性有问题

@Service
public class UserServiceImpl implements UserService {

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void update(User user) {
        // update user
    }    
}

回顾一下spring的事物传播行为

Spring 事务的传播行为说的是,当多个事务同时存在的时候, Spring 如何处理这些事务的行为。

类型说明
PROPAGATION_REQUIRED如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
PROPAGATION_SUPPORTS支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
PROPAGATION_MANDATORY支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
PROPAGATION_REQUIRES_NEW创建新事务,无论当前存不存在事务,都创建新事务。
PROPAGATION_NOT_SUPPORTED以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按 REQUIRED 属性执行。

当传播行为设置了PROPAGATION_NOT_SUPPORTED,PROPAGATION_NEVER,PROPAGATION_SUPPORTS这三种时,就有可能存在事物不生效。

2.6 异常被你 "抓住"了

@Service
public class UserServiceImpl implements UserService {

    @Transactional(rollbackFor = Exception.class)
    public void update(User user) {

      try{
        // update user
      }catch(Execption e){
         log.error("异常",e)
      }
    }    
}

异常被抓了,这样子代理类就没办法知道你到底有没有错误,需不需要回滚,所以这种情况也是没办法回滚的哦。

2.7 rollbackFor异常指定错误

@Service
public class UserServiceImpl implements UserService {

    @Transactional
    public void update(User user) {
        // update user
    }    
}

上面这种没有指定回滚异常,这个时候默认的回滚异常是RuntimeException ,如果出现其他异常那么就不会回滚事物。

Spring事务失效原因有以下几个可能: 1. 配置错误:在中,事务的管理是通过A和代理实现的。如果没有正确AOP或代理,事务将无法被管理和应用。例如,没有在文件中启用事务管理器或没有将@Transactional注解应用到需要事务管理的方法上。 2. 异常处理不当:如果在事务方法中抛出了未被捕获的异常,并且该异常没有被正确处理,事务将会回滚失败,从而导致事务失效。确保在事务方法中正确处理异常,或者使用Spring的声明式事务(@Transactional)来自动处理异常。 3. 事务传播性设置错误:Spring中的事务传播性定义了一个方法调用是否应该加入到已存在的事务中。如果事务传播性设置错误,可能会导致事务失效。例如,将一个具有REQUIRED_NEW传播性的方法调用插入到一个具有REQUIRED传播性的方法中,将会导致内部方法的事务失效。 4. 数据库引擎不支持事务:某些数据库引擎可能不支持事务,或者需要进行特殊的配置才能启用事务支持。如果使用的数据库引擎不支持事务,Spring的事务管理功能将无法生效。 5. 配置多数据源时的错误:如果项目中配置了多数据源,并且事务管理器没有正确指定数据源,事务将无法在正确的数据源上生效。 这些是导致Spring事务失效的常见原因,通过检查和排查这些可能性,通常可以解决事务失效的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值