Spring事物失效场景

环境配置

模块 版本
mysql 5.7.44
SpringBoot 2.1.3.RELEASE
Mybatis Plus 3.2.0
mysql-connector 8.0.28

    因为现在这家公司我在测试的时候发现出现了事物失效的情况,虽然调用的方法链路上都有Translate注解,但是依旧会出现事物会滚异常的情况。所以我想研究一下,看看这个代码到底是什么原因导致的事物失效。给各位打个点,不是因为方法内部调用导致的,本身方法内调用同类方法已经独立启动一个AopProxy。

事物失效的场景

1. 非public修饰的方法

        在Java中的访问权限有四种,private、default、protected、public。非public方法修饰的方法,就算加上Translate注解,事物也不会生效。失效的原因是 在AbstractFallbackTransactionAttributeSource类的computeTransactionAttribute方法中有个判断,如果目标方法不是public,则TransactionAttribute返回null,即不支持事务。

/**
 * 非public方法,Transactional注解失效,导致事物无效
 */
@Transactional
private void authTypeTranslateUnable(){
    mapper.insert(new TranslateTableA("a"));
    mapper.insert(new TranslateTableA("b"));

    // 数据库中应该不存在这两条数据
    throw new RuntimeException("抛出异常");
}

2. final修饰

        如果事物方法被final修饰,那么事物就会无效。原因是final修饰的方法无法进行动态代理,导致Spring无法通过动态代理实现事物。

/**
 * final 修饰,Transactional注解失效,导致事物无效
 */
@Transactional
public final void finalTypeTranslateUnable(){
    mapper.insert(new TranslateTableA("a"));
    mapper.insert(new TranslateTableA("b"));

    // 数据库中应该不存在这两条数据
    throw new RuntimeException("抛出异常");
}

3. 方法内部调用

        当调用方法没有开启事物,而被调用方法开启事物的时候,会导致被调用方的事物失效。同样是动态代理的原因,动态代理已经加到日后更新中,各位期待一下。这里简单解释一下为什么会失效,是因为在调用方法(innerMethodTranslateUnable)中,Spring已经生成动态代理类,之后调用innerMethodTranslateUnableStep2的时候,是在代理类中直接调用方法,所以Spring的Aop不会生效,就导致事物没有开启。但是如果我们在innerMethodTranslateUnable方法上添加事物,那么事物就会生效。

/**
 * 事物可以生效的情况
 */
@Transactional
public void innerMethodTranslateUnable(){
    this.innerMethodTranslateUnableStep2();
}

public void innerMethodTranslateUnableStep2(){
    mapper.insert(new TranslateTableA("innerMethodTranslateUnable-a"));
    throw new RuntimeException("抛出异常");
}

4. 未被Sping管理的Bean

        这个就没啥好解释的了,bean没有被Spring管理,那你用Spring的事物注解,那肯定不行的。

5. 多线程调用方法导致事物失效

        因为每一条线程获取到的数据库链接可能不一样,因为事物是针对一条数据库连接的,同一个事物无法在多条连接中实现

/**
 * 多线程调用导致事物失效
 * 因为每一条线程获取到的数据库链接可能不一样,因为事物是针对一条数据库连接的,同一个事物无法在多条连接中实现
 */
@Transactional
public void multThreadTranslateUnable(){
    mapper.insert(new TranslateTableA("multThreadTranslateUnable-a"));
    new Thread(() -> {
        threadComponent.saveInfo();
    }).start();
    new Thread(() -> {
        threadComponent.saveInfo();
    }).start();
    new Thread(() -> {
        threadComponent.saveInfo();
    }).start();
    new Thread(() -> {
        threadComponent.saveInfo();
    }).start();
    new Thread(() -> {
        threadComponent.saveInfo();
    }).start();

    throw new RuntimeException("抛出异常");
}

6.  异常不匹配或者异常被方法内部try cache

7.  方法设置了不支持事物

/**
 * 使用不开启事物,执行sql
 */
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void errorTranslatePropagationTranslateUnable(){
    mapper.insert(new TranslateTableA("innerPrivateMethodTranslateUnable-3"));
}

8.  mysql的数据引擎不支持事物,例如MyISAM

为啥业务代码中事物不生效呢?我明天补一下,今天我要搞一下socket的内容

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章