REQUIRES_NEW官方文档解释:
Create a new transaction, and suspend the current transaction if one exists.
意思是,创建一个新事务,如果当前存在事务,将这个事务挂起。也就是说如果当前存在事务,那么将当前的事务挂起,并开启一个新事务去执行REQUIRES_NEW标志的方法。
先来总结一下结果:
1.标志REQUIRES_NEW会新开启事务,外层事务不会影响内部事务的提交/回滚
2.标志REQUIRES_NEW的内部事务的异常,会影响外部事务的回滚
如下代码,PersonServiceImpl被标志使用事务,事务传播机制为REQUIRED,insert方法中调用了PersonOtherServiceImpl 类的insert2方法,而此insert2方法被标注REQUIRES_NEW。
@Service
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
public class PersonServiceImpl implements PersonService {
private static final Logger log = LoggerFactory.getLogger(PersonServiceImpl.class);
@Autowired
private PersonMapper personMapper ;
@Autowired
private PersonOtherService personOtherService ;
@Override
public void insert() {
log.info("start insert @@@@@@@@@@@@@@@@@");
Person p = new Person() ;
p.setId(1);
p.setName("one");
personOtherService.insert2();
int i = 1/0 ;
personMapper.insert(p) ;
log.info("end insert @@@@@@@@@@@@@@@@@");
}
}
@Service
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public class PersonOtherServiceImpl implements PersonOtherService {
private static final Logger log = LoggerFactory.getLogger(PersonOtherServiceImpl.class);
@Autowired
private PersonMapper personMapper ;
@Override
public void insert2() {
log.info("start update !!!!!!!!!!!!!!");
Person person = new Person() ;
person.setId(2);
person.setName("two");
personMapper.insert(person) ;
log.info("end update !!!!!!!!!!!!!!!");
}
}
我们表写单元测试进行测试:
@RunWith(SpringRunner.class)
@SpringBootTest
public class PropagationApplicationTests {
@Autowired
private PersonService personService ;
@Test
public void contextLoads() {
personService.insert();
}
}
控制台输出如下:
2018-10-30 15:05:33.364 DEBUG 10984 --- [ main] o.s.j.d.DataSourceTransactionManager : Creating new transaction with name [com.liu.transation.service.impl.PersonServiceImpl.insert]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-java.lang.Exception
2018-10-30 15:05:33.671 INFO 10984 --- [ main] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} inited
2018-10-30 15:05:33.675 DEBUG 10984 --- [ main] o.s.j.d.DataSourceTransactionManager : Acquired Connection [com.mysql.jdbc.JDBC4Connection@30922f8d] for JDBC transaction
2018-10-30 15:05:33.677 DEBUG 10984 --- [ main] o.s.j.d.DataSourceTransactionManager : Switching JDBC Connection [com.mysql.jdbc.JDBC4Connection@30922f8d] to manual commit
2018-10-30 15:05:33.677 INFO 10984 --- [ main] c.l.t.service.impl.PersonServiceImpl : start insert @@@@@@@@@@@@@@@@@
2018-10-30 15:05:33.677 DEBUG 10984 --- [ main] o.s.j.d.DataSourceTransactionManager : Suspending current transaction, creating new transaction with name [com.liu.transation.service.impl.PersonOtherServiceImpl.insert]
2018-10-30 15:05:33.677 DEBUG 10984 --- [ main] o.s.j.d.DataSourceTransactionManager : Acquired Connection [com.mysql.jdbc.JDBC4Connection@7fef0b40] for JDBC transaction
2018-10-30 15:05:33.677 DEBUG 10984 --- [ main] o.s.j.d.DataSourceTransactionManager : Switching JDBC Connection [com.mysql.jdbc.JDBC4Connection@7fef0b40] to manual commit
2018-10-30 15:05:33.677 INFO 10984 --- [ main] c.l.t.s.impl.PersonOtherServiceImpl : start update !!!!!!!!!!!!!!
2018-10-30 15:05:33.724 DEBUG 10984 --- [ main] c.l.t.m.PersonMapper.insertSelective : ==> Preparing: insert into person ( id, name ) values ( ?, ? )
2018-10-30 15:05:33.755 DEBUG 10984 --- [ main] c.l.t.m.PersonMapper.insertSelective : ==> Parameters: 2(Integer), two(String)
2018-10-30 15:05:33.771 DEBUG 10984 --- [ main] c.l.t.m.PersonMapper.insertSelective : <== Updates: 1
2018-10-30 15:05:33.771 INFO 10984 --- [ main] c.l.t.s.impl.PersonOtherServiceImpl : end update !!!!!!!!!!!!!!!
2018-10-30 15:05:33.771 DEBUG 10984 --- [ main] o.s.j.d.DataSourceTransactionManager : Initiating transaction commit
2018-10-30 15:05:33.771 DEBUG 10984 --- [ main] o.s.j.d.DataSourceTransactionManager : Committing JDBC transaction on Connection [com.mysql.jdbc.JDBC4Connection@7fef0b40]
2018-10-30 15:05:33.771 DEBUG 10984 --- [ main] o.s.j.d.DataSourceTransactionManager : Releasing JDBC Connection [com.mysql.jdbc.JDBC4Connection@7fef0b40] after transaction
2018-10-30 15:05:33.771 DEBUG 10984 --- [ main] o.s.jdbc.datasource.DataSourceUtils : Returning JDBC Connection to DataSource
2018-10-30 15:05:33.771 DEBUG 10984 --- [ main] o.s.j.d.DataSourceTransactionManager : Resuming suspended transaction after completion of inner transaction
2018-10-30 15:05:33.771 DEBUG 10984 --- [ main] o.s.j.d.DataSourceTransactionManager : Initiating transaction rollback
2018-10-30 15:05:33.771 DEBUG 10984 --- [ main] o.s.j.d.DataSourceTransactionManager : Rolling back JDBC transaction on Connection [com.mysql.jdbc.JDBC4Connection@30922f8d]
2018-10-30 15:05:33.771 DEBUG 10984 --- [ main] o.s.j.d.DataSourceTransactionManager : Releasing JDBC Connection [com.mysql.jdbc.JDBC4Connection@30922f8d] after transaction
2018-10-30 15:05:33.771 DEBUG 10984 --- [ main] o.s.jdbc.datasource.DataSourceUtils : Returning JDBC Connection to DataSource
java.lang.ArithmeticException: / by zero
//异常信息省略
分析一下输出结果,进入insert方法前开启一个事务,然后初始化数据源并取得一个Connection对象,在设置Connection手动提交事务,准备工作完成。进入insert方法,遇到insert2时,将当前事务挂起并创建一个新的事务,取得Connection,设置Connection手动提交事务,开始执行insert2的方法体,执行之后,提交insert2的事务并释放Connection放回数据库连接池,此方法执行结束。接下来回到insert方法中,唤醒insert的事务,接着执行insert的方法体,发现1/0抛出异常,事务进行回滚,但不会回滚insert2的事务。
如上代码,将i=1/0这行代码剪切到insert2方法中,则insert2会抛出异常,之后insert方法中的事务也会跟着rollback,控制台输入如下:
2018-10-30 15:21:05.964 DEBUG 10040 --- [ main] o.s.j.d.DataSourceTransactionManager : Creating new transaction with name [com.liu.transation.service.impl.PersonServiceImpl.insert]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-java.lang.Exception
2018-10-30 15:21:06.261 INFO 10040 --- [ main] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} inited
2018-10-30 15:21:06.261 DEBUG 10040 --- [ main] o.s.j.d.DataSourceTransactionManager : Acquired Connection [com.mysql.jdbc.JDBC4Connection@60bf494c] for JDBC transaction
2018-10-30 15:21:06.261 DEBUG 10040 --- [ main] o.s.j.d.DataSourceTransactionManager : Switching JDBC Connection [com.mysql.jdbc.JDBC4Connection@60bf494c] to manual commit
2018-10-30 15:21:06.277 INFO 10040 --- [ main] c.l.t.service.impl.PersonServiceImpl : start insert @@@@@@@@@@@@@@@@@
2018-10-30 15:21:06.324 DEBUG 10040 --- [ main] c.l.t.m.PersonMapper.insertSelective : ==> Preparing: insert into person ( id, name ) values ( ?, ? )
2018-10-30 15:21:06.355 DEBUG 10040 --- [ main] c.l.t.m.PersonMapper.insertSelective : ==> Parameters: 1(Integer), one(String)
2018-10-30 15:21:06.355 DEBUG 10040 --- [ main] c.l.t.m.PersonMapper.insertSelective : <== Updates: 1
2018-10-30 15:21:06.355 DEBUG 10040 --- [ main] o.s.j.d.DataSourceTransactionManager : Suspending current transaction, creating new transaction with name [com.liu.transation.service.impl.PersonOtherServiceImpl.insert]
2018-10-30 15:21:06.355 DEBUG 10040 --- [ main] o.s.j.d.DataSourceTransactionManager : Acquired Connection [com.mysql.jdbc.JDBC4Connection@3c81cd82] for JDBC transaction
2018-10-30 15:21:06.355 DEBUG 10040 --- [ main] o.s.j.d.DataSourceTransactionManager : Switching JDBC Connection [com.mysql.jdbc.JDBC4Connection@3c81cd82] to manual commit
2018-10-30 15:21:06.355 INFO 10040 --- [ main] c.l.t.s.impl.PersonOtherServiceImpl : start update !!!!!!!!!!!!!!
2018-10-30 15:21:06.355 DEBUG 10040 --- [ main] c.l.t.m.PersonMapper.insertSelective : ==> Preparing: insert into person ( id, name ) values ( ?, ? )
2018-10-30 15:21:06.355 DEBUG 10040 --- [ main] c.l.t.m.PersonMapper.insertSelective : ==> Parameters: 2(Integer), two(String)
2018-10-30 15:21:06.355 DEBUG 10040 --- [ main] c.l.t.m.PersonMapper.insertSelective : <== Updates: 1
2018-10-30 15:21:06.355 DEBUG 10040 --- [ main] o.s.j.d.DataSourceTransactionManager : Initiating transaction rollback
2018-10-30 15:21:06.355 DEBUG 10040 --- [ main] o.s.j.d.DataSourceTransactionManager : Rolling back JDBC transaction on Connection [com.mysql.jdbc.JDBC4Connection@3c81cd82]
2018-10-30 15:21:06.386 DEBUG 10040 --- [ main] o.s.j.d.DataSourceTransactionManager : Releasing JDBC Connection [com.mysql.jdbc.JDBC4Connection@3c81cd82] after transaction
2018-10-30 15:21:06.386 DEBUG 10040 --- [ main] o.s.jdbc.datasource.DataSourceUtils : Returning JDBC Connection to DataSource
2018-10-30 15:21:06.386 DEBUG 10040 --- [ main] o.s.j.d.DataSourceTransactionManager : Resuming suspended transaction after completion of inner transaction
2018-10-30 15:21:06.386 DEBUG 10040 --- [ main] o.s.j.d.DataSourceTransactionManager : Initiating transaction rollback
2018-10-30 15:21:06.386 DEBUG 10040 --- [ main] o.s.j.d.DataSourceTransactionManager : Rolling back JDBC transaction on Connection [com.mysql.jdbc.JDBC4Connection@60bf494c]
2018-10-30 15:21:06.386 DEBUG 10040 --- [ main] o.s.j.d.DataSourceTransactionManager : Releasing JDBC Connection [com.mysql.jdbc.JDBC4Connection@60bf494c] after transaction
2018-10-30 15:21:06.386 DEBUG 10040 --- [ main] o.s.jdbc.datasource.DataSourceUtils : Returning JDBC Connection to DataSource
java.lang.ArithmeticException: / by zero