Spring嵌套事物的简单测试

整体项目很简单,为了方便,用了Spring Boot和Mybatis集成的方式对数据库进行操作,事物的传播属性是默认的PROPAGATION_REQUIRED.这里最主要是Service外层和Service内层的嵌套,大概看看都能看懂(注:for循环从开始了,没做修改,忽略数据库id不能为的无用数据,操作过程中已删除)。

下面分情况介绍异常:

Application层(没用这个,直接用了Junit测试类)

---------------------------------------------------------------------------------------------------------------------------------

importorg.mybatis.spring.annotation.MapperScan;

importorg.springframework.boot.SpringApplication;

importorg.springframework.boot.autoconfigure.SpringBootApplication;

/**

* Created byshon 18/4/28.

*/

@SpringBootApplication

@MapperScan("com.sh.springboot.dao")

publicclassSpringbootApplication{

publicstaticvoidmain(String[]args) {

SpringApplication.run(SpringbootApplication.class,args);

}

/*

* @Autowired private ServiceWaiCeng s;

*

* @RequestMapping("/") String home()throws Exception {

*

* return "正常返回Hello World!"; }

*/

}

Test测试类

---------------------------------------------------------------------------------------------------------------------------------

importorg.junit.Test;

/**

* Created byshon 18/4/28.

*/

@RunWith(SpringJUnit4ClassRunner.class)

@SpringBootTest(classes = SpringbootApplication.class)

publicclassPersonDaoTest {

@Autowired

privateServiceWaiCengservicewaiceng;

@Test

publicvoidtest() {

servicewaiceng.insertWaiCeng();

}

}

---------------------------------------------------------------------------------------------------------------------------------

Service外层

---------------------------------------------------------------------------------------------------------------------------------

/**

* Created byshon 18/4/28.

*/

@Component

publicclassServiceWaiCengImplimplementsServiceWaiCeng {

@Autowired

privateServiceNeiCengsnc;

@Transactional

publicvoidinsertWaiCeng() {

for(intj= 0;j

snc.insertNeiCeng(j,j+"姓名");

}

}

}

---------------------------------------------------------------------------------------------------------------------------------

Service内层

---------------------------------------------------------------------------------------------------------------------------------

/**

* Created byshon 18/4/28.

*/

@Service

publicclassServiceNeiCengImplimplementsServiceNeiCeng {

@Autowired

PersonDaopersondao;

@Transactional

publicvoidinsertNeiCeng(intid, Stringname) {

Personperson=newPerson();

person.setId(id);

person.setName(name);

persondao.insertPerson(person);

}

}

---------------------------------------------------------------------------------------------------------------------------------

一、内外都无Try Catch

1.外部有异常,内部无异常

修改Service外层代码如下:

---------------------------------------------------------------------------------------------------------------------------------

/**

* Created byshon 18/4/28.

*/

@Component

publicclassServiceWaiCengImplimplementsServiceWaiCeng {

@Autowired

privateServiceNeiCengsnc;

@Transactional

publicvoidinsertWaiCeng() {

for(intj= 0;j

snc.insertNeiCeng(j,j+"姓名");

if(j== 4) {

inti= 2 / 0;//此处会产生异常

}

}

}

}

---------------------------------------------------------------------------------------------------------------------------------

打印执行结果:0~4内层正常执行

数据库结果:全部回滚

总结:内外都无try Catch的时候,外部异常,全部回滚。

2.外部无异常,内部有异常

注掉Service外层的异常部分,修改Service内层代码如下:

---------------------------------------------------------------------------------------------------------------------------------

/**

* Created byshon 18/4/28.

*/

@Service

publicclassServiceNeiCengImplimplementsServiceNeiCeng {

@Autowired

PersonDaopersondao;

@Transactional

publicvoidinsertNeiCeng(intid, Stringname) {

Personperson=newPerson();

person.setId(id);

person.setName(name);

persondao.insertPerson(person);

if(id== 4) {

inti= 2 / 0;//此处会产生异常

}

}

}

---------------------------------------------------------------------------------------------------------------------------------

打印执行结果:0~3内层正常执行

数据库结果:全部回滚

总结:内外都无try Catch的时候,内部异常,全部回滚。

内外都有异常,由1和2可得,内部先异常,不用考虑外部异常也都是全部回滚。

二、内外都有Try Catch

1.外部有异常,内部无异常

修改Service内层和外层代码如下:

---------------------------------------------------------------------------------------------------------------------------------

/**

* Created byshon 18/4/28.

*/

@Component

publicclassServiceWaiCengImplimplementsServiceWaiCeng {

@Autowired

privateServiceNeiCengsnc;

@Transactional

publicvoidinsertWaiCeng() {

try{

for(intj= 0;j

snc.insertNeiCeng(j,j+"姓名");

if(j== 4) {

inti= 2 / 0;//此处会产生异常

}

}

}catch(Exceptione) {

}

}

}

---------------------------------------------------------------------------------------------------------------------------------

/**

* Created byshon 18/4/28.

*/

@Service

publicclassServiceNeiCengImplimplementsServiceNeiCeng {

@Autowired

PersonDaopersondao;

@Transactional

publicvoidinsertNeiCeng(intid,Stringname) {

try{

Personperson=newPerson();

person.setId(id);

person.setName(name);

persondao.insertPerson(person);

// if(id == 4) {

//inti = 2 / 0;//此处会产生异常

// }

}catch(Exceptione) {

}

}

}

---------------------------------------------------------------------------------------------------------------------------------

打印执行结果:0~4内层正常打印,外层异常处理并且正常执行

数据库结果:插入四条数据,没有回滚

总结:内外都有tryCatch,外部异常,事物失败(走一半)

2.外部无异常,内部有异常

修改Service内层和外层代码如下:

---------------------------------------------------------------------------------------------------------------------------------

/**

* Created byshon 18/4/28.

*/

@Component

publicclassServiceWaiCengImplimplementsServiceWaiCeng {

@Autowired

privateServiceNeiCengsnc;

@Transactional

publicvoidinsertWaiCeng() {

try{

for(intj= 0;j

snc.insertNeiCeng(j,j+"姓名");

// if(j == 4) {

//inti = 2 / 0;//此处会产生异常

// }

}

}catch(Exceptione) {

}

}

}

---------------------------------------------------------------------------------------------------------------------------------

/**

* Created byshon 18/4/28.

*/

@Service

publicclassServiceNeiCengImplimplementsServiceNeiCeng {

@Autowired

PersonDaopersondao;

@Transactional

publicvoidinsertNeiCeng(intid, Stringname) {

try{

Personperson=newPerson();

person.setId(id);

person.setName(name);

persondao.insertPerson(person);

if(id== 4) {

inti= 2 / 0;//此处会产生异常

}

}catch(Exceptione) {

}

}

}

---------------------------------------------------------------------------------------------------------------------------------

打印执行结果:0~7内层打印正常,4内层异常处理,

数据库结果:

总结:内外都有tryCatch,内部异常,事物失败(数据全部插入)

内外都有异常,由1和2可得,先走内部异常,再外部异常,数据结果同1

三、外层有Try Catch,内层无Try Catch

1.外部有异常,内部无异常

修改Service内层和外层代码如下:

---------------------------------------------------------------------------------------------------------------------------------

/**

* Created byshon 18/4/28.

*/

@Service

publicclassServiceNeiCengImplimplementsServiceNeiCeng {

@Autowired

PersonDaopersondao;

@Transactional

publicvoidinsertNeiCeng(intid, Stringname) {

Personperson=newPerson();

person.setId(id);

person.setName(name);

persondao.insertPerson(person);

// if(id == 4) {

//inti = 2 / 0;//此处会产生异常

// }

}

}

/**

* Created byshon 18/4/28.

*/

@Component

publicclassServiceWaiCengImplimplementsServiceWaiCeng {

@Autowired

privateServiceNeiCengsnc;

@Transactional

publicvoidinsertWaiCeng() {

try{

for(intj= 0;j

snc.insertNeiCeng(j,j+"姓名");

if(j== 4) {

inti= 2 / 0;//此处会产生异常

}

}

}catch(Exceptione) {

}

}

}

---------------------------------------------------------------------------------------------------------------------------------

打印执行结果:0~4内层正常执行,外层异常处理继续正常执行流程到结束

数据库结果:4条数据正常插入

总结:外部有try Catch、内部无try Catch的时候,外部异常,不能回滚(事物错误)

2.外部无异常,内部有异常

修改Service内层和外层代码如下:

---------------------------------------------------------------------------------------------------------------------------------

/**

* Created byshon 18/4/28.

*/

@Service

publicclassServiceNeiCengImplimplementsServiceNeiCeng {

@Autowired

PersonDaopersondao;

@Transactional

publicvoidinsertNeiCeng(intid, Stringname) {

Personperson=newPerson();

person.setId(id);

person.setName(name);

persondao.insertPerson(person);

if(id== 4) {

inti= 2 / 0;//此处会产生异常

}

}

}

---------------------------------------------------------------------------------------------------------------------------------

/**

* Created byshon 18/4/28.

*/

@Component

publicclassServiceWaiCengImplimplementsServiceWaiCeng {

@Autowired

privateServiceNeiCengsnc;

@Transactional

publicvoidinsertWaiCeng() {

try{

for(intj= 0;j

snc.insertNeiCeng(j,j+"姓名");

// if(j == 4) {

//inti = 2 / 0;//此处会产生异常

// }

}

}catch(Exceptione) {

}

}

}

---------------------------------------------------------------------------------------------------------------------------------

打印执行结果:0~3内层正常打印执行

数据库结果:无数据,全部回滚

总结:外部有try Catch、内部无try Catch的时候,内部异常,全部回滚

内外都有异常,由1和2推理得结果也是事物失败。

四、外层无Try Catch,内层有Try Catch

1.外部有异常,内部无异常

修改Service内层和外层代码如下:

---------------------------------------------------------------------------------------------------------------------------------

/**

* Created byshon 18/4/28.

*/

@Service

publicclassServiceNeiCengImplimplementsServiceNeiCeng {

@Autowired

PersonDaopersondao;

@Transactional

publicvoidinsertNeiCeng(intid, Stringname) {

try{

Personperson=newPerson();

person.setId(id);

person.setName(name);

persondao.insertPerson(person);

// if(id == 4) {

//inti = 2 / 0;//此处会产生异常

// }

}catch(Exceptione) {

}

}

}

---------------------------------------------------------------------------------------------------------------------------------

/**

* Created byshon 18/4/28.

*/

@Component

publicclassServiceWaiCengImplimplementsServiceWaiCeng {

@Autowired

privateServiceNeiCengsnc;

@Transactional

publicvoidinsertWaiCeng() {

for(intj= 0;j

snc.insertNeiCeng(j,j+"姓名");

if(j== 4) {

inti= 2 / 0;//此处会产生异常

}

}

}

}

---------------------------------------------------------------------------------------------------------------------------------

打印执行结果:0~4内层打印正常,外层不打印

数据库结果:

总结:外部无try Catch、内部有try Catch的时候,外部异常,全部回滚

2.外部无异常,内部有异常

修改Service内层和外层代码如下:

---------------------------------------------------------------------------------------------------------------------------------

/**

* Created byshon 18/4/28.

*/

@Service

publicclassServiceNeiCengImplimplementsServiceNeiCeng {

@Autowired

PersonDaopersondao;

@Transactional

publicvoidinsertNeiCeng(intid, Stringname) {

try{

Personperson=newPerson();

person.setId(id);

person.setName(name);

persondao.insertPerson(person);

if(id== 4) {

inti= 2 / 0;//此处会产生异常

}

}catch(Exceptione) {

}

}

}

---------------------------------------------------------------------------------------------------------------------------------

/**

* Created byshon 18/4/28.

*/

@Component

publicclassServiceWaiCengImplimplementsServiceWaiCeng {

@Autowired

privateServiceNeiCengsnc;

@Transactional

publicvoidinsertWaiCeng() {

for(intj= 0;j

snc.insertNeiCeng(j,j+"姓名");

// if(j == 4) {

//inti = 2 / 0;//此处会产生异常

// }

}

}

}

---------------------------------------------------------------------------------------------------------------------------------

打印执行结果:0~7内层打印执行正常,4内层有异常、被处理了,外层也正常打印

数据库结果:全部插入,无回滚

总结:外部无try Catch、内部有try Catch的时候,内部异常,事物失败(全部没有回滚)

内外都异常:不用测了,结果是全部回滚,原因在后面有说明。

汇总以上8条(内外都异常自己思考,在此不做过多解释,后面的解释对内外都异常的情况也是有效的):

1.内外都无try Catch的时候,外部异常,全部回滚;

2.内外都无try Catch的时候,内部异常,全部回滚;

3.内外都有try Catch,外部异常,事物失败(走一半);

4.内外都有try Catch,内部异常,事物失败(数据全部插入);

5.外部有try Catch、内部无try Catch的时候,外部异常,不能回滚(事物错误);

6.外部有try Catch、内部无try Catch的时候,内部异常,全部回滚;

7.外部无try Catch、内部有try Catch的时候,外部异常,全部回滚;

8.外部无try Catch、内部有try Catch的时候,内部异常,事物失败(全部没有回滚)。

实际上,Service外层的insertWaiCeng()调用Service内层的 insertNeiCeng(int id, String name),由于spring事物的传播属性为默认的PROPAGATION_REQUIRED,所以执行Service外层的 insertWaiCeng() 的时候spring已经起了事务,这时调用Service内层的 insertNeiCeng(int id, Stringname),Service内层的insertNeiCeng(intid, String name)看到自己已经运行在 Service外层的insertWaiCeng()的事务内部,就不再起新的事务。假如Service内层的insertNeiCeng(int id, String name)运行的时候发现自己没有在事务中,他就会为自己分配一个事务。这样,在Service外层的insertWaiCeng()或者在Service内层的insertNeiCeng(int id, String name)内的任何地方出现异常,事务都会被回滚。

上面8条中的1、2、6、7事物可以成功。1很好理解,外部无try Catch且有异常直接全部回滚;2是内部异常抛给了调用者即外层,和1同理;6是外部有try Catch,所以内部自己分配一个事物,有异常则回滚;7同1。

3是内部不起事物,外部异常,无法回滚;4是异常全被处理了,所以数据会全部插入(事务失败);5和3一样,内部本身无异常,处理不处理都一样;8是内部的异常全被内部的try Catch处理了,所以事务失败。

附:外层方法中调取其他接口或者另外开启线程的操作,由于调取接口不能回滚,一定要放到最后来处理。

项目git地址:https://github.com/scarlett-8/springTransactional-

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180430G03ATZ00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券