您的位置:首页 > 产品设计 > UI/UE

sp:Propagation.REQUIRED vs Propagation.REQUIRES_NEW

2016-05-04 17:16 471 查看

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=
4000
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,异常就是这样来的。

至于如何实现,暂时先不考虑了,借此聊以慰藉。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: