spring transaction propagation:Propagation.REQUIRED vs Propagation.REQUIRES_NEW

Introduction

spring事务propagation(事务传播特性)配置,常用的配置项为Propagation.REQUIRED或者Propagation.REQUIRES_NEW。

Propagation.REQUIRED:如果当前有事务,则在当前事务中执行,如果没有事务,则创建一个事务执行。
Propagation.REQUIRES_NEW:无论如何创建一个新的事务执行。

这里的事务指的是数据库层面的事务(physical transaction)

如果在当前事务中,调用有@Transactional(Propagation.REQUIRED/REQUIRES_NEW)配置的方法,在该方法中触发了事务回滚条件,由于REQUIRED在当前事务中执行,所以当前事务会回滚,而REQUIRES_NEW新建一个事务,所以新建的事务会回滚,而当前事务是否回滚与此无关。

REQUIRED

@Service
public class TestServiceImpl02 implements TestService {
    @Autowired
    private SmsUserMapper smsUserMapper;
    @Autowired
    private TestService testServiceImpl01;

    @Override
    @Transactional(propagation=Propagation.REQUIRED)
    public void test() {
        SmsUser user = new SmsUser();
        user.setUserAccount("baizq000");
        user.setUserPwd("000000");
        user.setUserStatus(0);
        user.setPlatformName("xxx");
        smsUserMapper.insert(user);
        testServiceImpl01.test();//在当前事务中调用下面的Propagation.REQUIRED方法
    }
}
@Service
public class TestServiceImpl01 implements TestService {
    @Override
    @Transactional(propagation=Propagation.REQUIRED)
    public void test(){
        throw new RuntimeException("xxx");
    }
}

调用TestServiceImpl02 .test()
结果:默认的rollbackFor RuntimeException导致testServiceImpl01.test()事务回滚,从而导致外部的事务(其实是同一个事务)也回滚,插入失败

打印的日志大概是这样:
Participating in existing transaction
Participating transaction failed - marking existing transaction as rollback-only
Initiating transaction rollback
Rolling back JDBC transaction on Connection[jdbc:mysql://…
Returning JDBC Connection to DataSource

REQUIRES_NEW

@Service
public class TestServiceImpl02 implements TestService {
    @Autowired
    private SmsUserMapper smsUserMapper;
    @Autowired
    private TestService testServiceImpl01;

    @Override
    @Transactional(propagation=Propagation.REQUIRED)
    public void test() {
        SmsUser user = new SmsUser();
        user.setUserAccount("baizq000");
        user.setUserPwd("000000");
        user.setUserStatus(0);
        user.setPlatformName("xxx");
        smsUserMapper.insert(user);
        try{
            testServiceImpl01.test();//在当前事务中调用下面的Propagation.REQUIRES_NEW方法
        }catch(RuntimeException e){
            e.printStackTrace();
        }
    }
}
@Service
public class TestServiceImpl01 implements TestService {
    @Override
    @Transactional(propagation=Propagation.REQUIRES_NEW)
    public void test(){
        throw new RuntimeException("xxx");
    }
}

调用TestServiceImpl02 .test()
结果,默认的rollbackFor RuntimeException导致testServiceImpl01.test()事务回滚,由于配置了REQUIRES_NEW,该事务为新的事务,与外部事务无关,观察外部事务,并不会触发回滚条件,所以外部事物可以成功执行,插入成功。
打印的日志大概是这样:

Suspending current transaction, creating new transaction with name [com.qyd.sms….
Resuming suspended transaction after completion of inner transaction
Initiating transaction commit
Committing JDBC transaction on Connection [jdbc:mysql://….

UnexpectedRollbackException

@Service
public class TestServiceImpl02 implements TestService {
    @Autowired
    private SmsUserMapper smsUserMapper;
    @Autowired
    private TestService testServiceImpl01;

    @Override
    @Transactional(propagation=Propagation.REQUIRED)
    public void test() {
        SmsUser user = new SmsUser();
        user.setUserAccount("baizq000");
        user.setUserPwd("000000");
        user.setUserStatus(0);
        user.setPlatformName("xxx");
        smsUserMapper.insert(user);
        try{
            testServiceImpl01.test();
            //在当前事务中调用下面的Propagation.REQUIRED方法,与之前不同的是这里对异常做了处理。
        }catch(RuntimeException e){
            e.printStackTrace();
        }
    }
}
@Service
public class TestServiceImpl01 implements TestService {
    @Override
    @Transactional(propagation=Propagation.REQUIRED)
    public void test(){
        throw new RuntimeException("xxx");
    }
}

调用TestServiceImpl02 .test()
会有如下的异常输出:
org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

当调用testServiceImpl01.test();会导致当前事务被设置为rollback-only(从REQUIRED章节的日志–Participating transaction failed - marking existing transaction as rollback-only),
而外部事务对异常的处理,导致外部事务看不到异常,所以外部事务会认为当前事务是没有问题的,要执行提交操作,但是由于之前当前事务已经被设置为rollback-only,异常就是这样来的。
至于如何实现,暂时先不考虑了,借此聊以慰藉。

你可能感兴趣的:(spring transaction propagation:Propagation.REQUIRED vs Propagation.REQUIRES_NEW)