2

spring的事务传播机制 - 源灬点

 1 year ago
source link: https://www.cnblogs.com/yuandian8/p/17347777.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

spring的事务传播机制

嫌弃内容代码复杂的可直接看思维导图大纲即可

1482762-20230423211409360-1579643024.png

指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行

七种行为和测试

PROPAGATION_REQUIRED

默认,当前存在事务,则加入该事务;不存在事务,创建新事务。

public class PropagationService {

    @Autowired
    private
    PropagationMapper propagationMapper;

    @Autowired
    @Lazy
    PropagationService propagationService;

    @Transactional(rollbackFor = Exception.class)
    public void insertPropagationA() throws Exception {
        Propagation propagationA = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationA").build();
        propagationMapper.insert(propagationA);
        propagationServiceSelf.insertPropagationB();
        throw new Exception();
    }

    @Transactional(rollbackFor = Exception.class,propagation = org.springframework.transaction.annotation.Propagation.REQUIRED)
    public void insertPropagationB() throws Exception {
        Propagation propagationB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationB").build();
        Propagation propagationBB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationBB").build();
        propagationMapper.insert(propagationB);
        propagationMapper.insert(prop
@Test
    //Given A传播行为required 和B为required,WHE A发生异常,THEN A插入失败,B插入失败
    public void testRequired() throws Exception {
        propagationService.insertPropagationA();
    }

PROPAGATION_REQUIRED_NEW

始终以新的事务运行,当前存在事务,则挂起原事务;不存在事务,创建新事务

@Test
    //Given 同样代码更改B为required_new, WHE A发生异常, THEN B插入成功,A插入失败
    public void testRequiredNew() throws Exception {
        propagationService.insertPropagationA();
    }

PROPAGATION_SUPPORTS

支持当前事务。当前存在事务,则支持该事务;不存在事务,以非事务方式执行

    @Test
    //Given 更改B为required_supports, A不开启事物, WHE B发生异常, THEN A、B插入成功BB失败;A开启事物因为有异常发生全失败
    public void testRequiredSupports() throws Exception {
        propagationService.insertPropagationA();
    }
//@Transactional(rollbackFor = Exception.class)
    public void insertPropagationA() throws Exception {
        Propagation propagationA = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationA").build();
        propagationMapper.insert(propagationA);
        propagationServiceSelf.insertPropagationB();
        throw new Exception();
    }

    @Transactional(rollbackFor = Exception.class,propagation = org.springframework.transaction.annotation.Propagation.SUPPORTS)
    public void insertPropagationB() throws Exception {
        Propagation propagationB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationB").build();
        Propagation propagationBB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationBB").build();
        propagationMapper.insert(propagationB);
        int a =  1/0;
        propagationMapper.insert(propagationBB);
    }

PROPAGATION_NO_SUPPORTED

非事务方式执行,当前存在事务,则挂起该事务

    @Test
    //Given 更改B为required_not_supports, A开启事物, WHEN A发生异常, THEN A插入失败、B插入成功
    public void testRequiredNotSupports() throws Exception {
        propagationService.insertPropagationA();
    }
    @Transactional(rollbackFor = Exception.class)
    public void insertPropagationA() throws Exception {
        Propagation propagationA = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationA").build();
        propagationMapper.insert(propagationA);
        propagationServiceSelf.insertPropagationB();
        throw new Exception();
    }

    @Transactional(rollbackFor = Exception.class,propagation = org.springframework.transaction.annotation.Propagation.NOT_SUPPORTED)
    public void insertPropagationB() throws Exception {
        Propagation propagationB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationB").build();
        Propagation propagationBB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationBB").build();
        propagationMapper.insert(propagationB);
        propagationMapper.insert(propagationBB);
    }

PROPAGATION_NEVER

非事务方式执行,当前存在事务,则抛出异常();

org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'

at org.springframework.transaction.support.AbstractPlatformTransactionManager.handleExistingTransaction(AbstractPlatformTransactionManager.java:413)
    @Transactional(rollbackFor = Exception.class)
    public void insertPropagationA() throws Exception {
        Propagation propagationA = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationA").build();
        propagationMapper.insert(propagationA);
        propagationServiceSelf.insertPropagationB();
        //throw new Exception();
    }

    @Transactional(rollbackFor = Exception.class,propagation = org.springframework.transaction.annotation.Propagation.NEVER)
    public void insertPropagationB() throws Exception {
        Propagation propagationB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationB").build();
        Propagation propagationBB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationBB").build();
        propagationMapper.insert(propagationB);
        propagationMapper.insert(propagationBB);
    }
    @Test
    //Given 更改B为required_never, A开启事物, 调用方法B时报错
    public void testRequiredNever() throws Exception {
        propagationService.insertPropagationA();
    }

PROPAGATION_NESTED

当前存在事务,则嵌套在该事务下起新事务执行;不存在事务,创建新事务。

    @Test
    //Given 更改B为required_nested, A开启事物, 调用方法B,后抛出异常,都失败;A开启事物,调用方法B,B抛出异常,A catch,A成功,B失败
    public void testRequiredNested() throws Exception {
        propagationService.insertPropagationA();
    }
    @Transactional(rollbackFor = Exception.class)
    public void insertPropagationA() throws Exception {
        Propagation propagationA = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationA").build();
        propagationMapper.insert(propagationA);
        try{
            propagationServiceSelf.insertPropagationB();
        }catch(Exception e){

        }
    }

    @Transactional(rollbackFor = Exception.class,propagation = org.springframework.transaction.annotation.Propagation.NESTED)
    public void insertPropagationB() throws Exception {
        Propagation propagationB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationB").build();
        Propagation propagationBB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationBB").build();
        propagationMapper.insert(propagationB);
        int a = 1/0;
        propagationMapper.insert(propagationBB);
    }

PROPAGATION_MANDATORY

事务方式运行,当前不存在事务,则抛出异常

org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'

at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:362)
//@Transactional(rollbackFor = Exception.class)
    public void insertPropagationA() throws Exception {
        Propagation propagationA = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationA").build();
        propagationMapper.insert(propagationA);
        propagationServiceSelf.insertPropagationB();

    }

    @Transactional(rollbackFor = Exception.class,propagation = org.springframework.transaction.annotation.Propagation.MANDATORY)
    public void insertPropagationB() throws Exception {
        Propagation propagationB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationB").build();
        Propagation propagationBB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationBB").build();
        propagationMapper.insert(propagationB);
        propagationMapper.insert(propagationBB);
    }
    @Test
    //Given 更改B为required_mandatory, WHEN A不开启事物,调用方法B, THEN调用B抛出异常;
    public void testRequiredMandatory() throws Exception {
        propagationService.insertPropagationA();
    }

Transactional失效

spring的事物是基于AOP代理实现的,也就是说背@Transactional修饰的方法所在类会有一个代理类,通过这个代理类实现的。并且也需要底层数据库支持事物,还需要在同一个库中,多个方法运行调用需要在同一个线程中。基于这情况大概失效场景分为两部分

非代理类方向

  • 数据库引擎不支持索引如MyISAm

  • 数据源未配置事物管理器

  • 数据库分布式部署,需要Seata技术解决

  • 多线程,两个事务方法不在同一个线程

代理类方向

  • 类未交给spring,代理自然无法生成

  • 自身调用,相当于this,代理类未生效

  • 事务方法修饰如非public、final、static修饰导致不能被代理

  • 异常类型错误,声明式事务默认对runtimeException、Error才可以触发回滚

  • 对抛出的异常,catch后处理不当。如吞了异常。

  • 设置了错误的传播行为


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK