整体项目很简单,为了方便,用了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-
领取专属 10元无门槛券
私享最新 技术干货