整体项目很简单,为了方便,用了Spring Boot和Mybatis集成的方式对数据库进行操作,事物的传播属性是默认的PROPAGATION_REQUIRED.这里最主要是Service外层和Service内层的嵌套,大概看看都能看懂(注:for循环从0开始了,没做修改,忽略数据库id不能为0的无用数据,操作过程中已删除)。
下面分情况介绍异常:
Application层(没用这个,直接用了Junit测试类)
---------------------------------------------------------------------------------------------------------------------------------
package com.sh.springboot;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Created by sh on 18/4/28.
*/
@SpringBootApplication
@MapperScan("com.sh.springboot.dao")
publicclassSpringbootApplication{
publicstaticvoid main(String[] args) {
SpringApplication.run(SpringbootApplication.class, args);
}
/*
* @Autowired private ServiceWaiCeng s;
*
* @RequestMapping("/") String home()throws Exception {
* System.out.println("controller 正常执行"); s.insertWaiCeng();;
*
* return " 正常返回Hello World!"; }
*/
}
Test测试类
---------------------------------------------------------------------------------------------------------------------------------
package com.sh.springboot;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.sh.springboot.servicewaiceng.ServiceWaiCeng;
/**
* Created by sh on 18/4/28.
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = SpringbootApplication.class)
publicclassPersonDaoTest {
@Autowired
private ServiceWaiCeng servicewaiceng;
@Test
publicvoid test() {
servicewaiceng.insertWaiCeng();
System.out.println("Controller正常执行");
}
}
---------------------------------------------------------------------------------------------------------------------------------
Service外层
---------------------------------------------------------------------------------------------------------------------------------
package com.sh.springboot.servicewaiceng.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.sh.springboot.serviceneiceng.ServiceNeiCeng;
import com.sh.springboot.servicewaiceng.ServiceWaiCeng;
/**
* Created by sh on 18/4/28.
*/
@Component
publicclassServiceWaiCengImpl implements ServiceWaiCeng {
@Autowired
private ServiceNeiCeng snc;
@Transactional
publicvoid insertWaiCeng() {
for (intj = 0; j < 8; j++) {
snc.insertNeiCeng(j, j + "姓名");
}
System.out.println("外层正常执行");
}
}
---------------------------------------------------------------------------------------------------------------------------------
Service内层
---------------------------------------------------------------------------------------------------------------------------------
package com.sh.springboot.serviceneiceng.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.sh.springboot.bean.Person;
import com.sh.springboot.dao.PersonDao;
import com.sh.springboot.serviceneiceng.ServiceNeiCeng;
/**
* Created by sh on 18/4/28.
*/
@Service
publicclassServiceNeiCengImpl implements ServiceNeiCeng {
@Autowired
PersonDaopersondao;
@Transactional
publicvoid insertNeiCeng(intid, String name) {
Personperson= newPerson();
person.setId(id);
person.setName(name);
persondao.insertPerson(person);
System.out.println(id + "内层正常执行");
}
}
---------------------------------------------------------------------------------------------------------------------------------
一、内外都无Try Catch
1.外部有异常,内部无异常
修改Service外层代码如下:
---------------------------------------------------------------------------------------------------------------------------------
package com.sh.springboot.servicewaiceng.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.sh.springboot.serviceneiceng.ServiceNeiCeng;
import com.sh.springboot.servicewaiceng.ServiceWaiCeng;
/**
* Created by sh on 18/4/28.
*/
@Component
publicclassServiceWaiCengImpl implements ServiceWaiCeng {
@Autowired
private ServiceNeiCeng snc;
@Transactional
publicvoid insertWaiCeng() {
for (intj = 0; j < 8; j++) {
snc.insertNeiCeng(j, j + "姓名");
if (j == 4) {
inti = 2 / 0;// 此处会产生异常
}
}
System.out.println("外层正常执行");
}
}
---------------------------------------------------------------------------------------------------------------------------------
打印执行结果:0~4内层正常执行
数据库结果:全部回滚
总结:内外都无try Catch的时候,外部异常,全部回滚。
2.外部无异常,内部有异常
注掉Service外层的异常部分,修改Service内层代码如下:
---------------------------------------------------------------------------------------------------------------------------------
package com.sh.springboot.serviceneiceng.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.sh.springboot.bean.Person;
import com.sh.springboot.dao.PersonDao;
import com.sh.springboot.serviceneiceng.ServiceNeiCeng;
/**
* Created by sh on 18/4/28.
*/
@Service
publicclassServiceNeiCengImpl implements ServiceNeiCeng {
@Autowired
PersonDaopersondao;
@Transactional
publicvoid insertNeiCeng(intid, String name) {
Personperson= newPerson();
person.setId(id);
person.setName(name);
persondao.insertPerson(person);
if (id == 4) {
inti = 2 / 0;// 此处会产生异常
}
System.out.println(id + "内层正常执行");
}
}
---------------------------------------------------------------------------------------------------------------------------------
打印执行结果:0~3内层正常执行
数据库结果:全部回滚
总结:内外都无try Catch的时候,内部异常,全部回滚。
内外都有异常,由1和2可得,内部先异常,不用考虑外部异常也都是全部回滚。
二、内外都有Try Catch
1.外部有异常,内部无异常
修改Service内层和外层代码如下:
---------------------------------------------------------------------------------------------------------------------------------
package com.sh.springboot.servicewaiceng.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.sh.springboot.serviceneiceng.ServiceNeiCeng;
import com.sh.springboot.servicewaiceng.ServiceWaiCeng;
/**
* Created by sh on 18/4/28.
*/
@Component
publicclassServiceWaiCengImpl implements ServiceWaiCeng {
@Autowired
private ServiceNeiCeng snc;
@Transactional
publicvoid insertWaiCeng() {
try {
for (intj = 0; j < 8; j++) {
snc.insertNeiCeng(j, j + "姓名");
if (j == 4) {
inti = 2 / 0;// 此处会产生异常
}
}
}catch(Exception e) {
System.out.println("外层异常处理");
}
System.out.println("外层正常执行");
}
}
---------------------------------------------------------------------------------------------------------------------------------
package com.sh.springboot.serviceneiceng.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.sh.springboot.bean.Person;
import com.sh.springboot.dao.PersonDao;
import com.sh.springboot.serviceneiceng.ServiceNeiCeng;
/**
* Created by sh on 18/4/28.
*/
@Service
publicclassServiceNeiCengImpl implements ServiceNeiCeng {
@Autowired
PersonDaopersondao;
@Transactional
publicvoid insertNeiCeng(intid, String name) {
try {
Personperson= newPerson();
person.setId(id);
person.setName(name);
persondao.insertPerson(person);
// if(id == 4) {
// inti = 2 / 0;// 此处会产生异常
// }
}catch(Exception e) {
System.out.println(id + "内部异常日志处理");
}
System.out.println(id + "内层正常执行");
}
}
---------------------------------------------------------------------------------------------------------------------------------
打印执行结果:0~4内层正常打印,外层异常处理并且正常执行
数据库结果:插入四条数据,没有回滚
总结:内外都有tryCatch,外部异常,事物失败(走一半)
2.外部无异常,内部有异常
修改Service内层和外层代码如下:
---------------------------------------------------------------------------------------------------------------------------------
package com.sh.springboot.servicewaiceng.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.sh.springboot.serviceneiceng.ServiceNeiCeng;
import com.sh.springboot.servicewaiceng.ServiceWaiCeng;
/**
* Created by sh on 18/4/28.
*/
@Component
publicclassServiceWaiCengImpl implements ServiceWaiCeng {
@Autowired
private ServiceNeiCeng snc;
@Transactional
publicvoid insertWaiCeng() {
try {
for (intj = 0; j < 8; j++) {
snc.insertNeiCeng(j, j + "姓名");
// if(j == 4) {
// inti = 2 / 0;// 此处会产生异常
// }
}
}catch(Exception e) {
System.out.println("外层异常处理");
}
System.out.println("外层正常执行");
}
}
---------------------------------------------------------------------------------------------------------------------------------
package com.sh.springboot.serviceneiceng.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.sh.springboot.bean.Person;
import com.sh.springboot.dao.PersonDao;
import com.sh.springboot.serviceneiceng.ServiceNeiCeng;
/**
* Created by sh on 18/4/28.
*/
@Service
publicclassServiceNeiCengImpl implements ServiceNeiCeng {
@Autowired
PersonDaopersondao;
@Transactional
publicvoid insertNeiCeng(intid, String name) {
try {
Personperson= newPerson();
person.setId(id);
person.setName(name);
persondao.insertPerson(person);
if (id == 4) {
inti = 2 / 0;// 此处会产生异常
}
}catch(Exception e) {
System.out.println(id + "内部异常日志处理");
}
System.out.println(id + "内层正常执行");
}
}
---------------------------------------------------------------------------------------------------------------------------------
打印执行结果:0~7内层打印正常,4内层异常处理,
数据库结果:
总结:内外都有tryCatch,内部异常,事物失败(数据全部插入)
内外都有异常,由1和2可得,先走内部异常,再外部异常,数据结果同1
三、外层有Try Catch,内层无Try Catch
1.外部有异常,内部无异常
修改Service内层和外层代码如下:
---------------------------------------------------------------------------------------------------------------------------------
package com.sh.springboot.serviceneiceng.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.sh.springboot.bean.Person;
import com.sh.springboot.dao.PersonDao;
import com.sh.springboot.serviceneiceng.ServiceNeiCeng;
/**
* Created by sh on 18/4/28.
*/
@Service
publicclassServiceNeiCengImpl implements ServiceNeiCeng {
@Autowired
PersonDaopersondao;
@Transactional
publicvoid insertNeiCeng(intid, String name) {
Personperson= newPerson();
person.setId(id);
person.setName(name);
persondao.insertPerson(person);
// if(id == 4) {
// inti = 2 / 0;// 此处会产生异常
// }
System.out.println(id + "内层正常执行");
}
}
package com.sh.springboot.servicewaiceng.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.sh.springboot.serviceneiceng.ServiceNeiCeng;
import com.sh.springboot.servicewaiceng.ServiceWaiCeng;
/**
* Created by sh on 18/4/28.
*/
@Component
publicclassServiceWaiCengImpl implements ServiceWaiCeng {
@Autowired
private ServiceNeiCeng snc;
@Transactional
publicvoid insertWaiCeng() {
try {
for (intj = 0; j < 8; j++) {
snc.insertNeiCeng(j, j + "姓名");
if (j == 4) {
inti = 2 / 0;// 此处会产生异常
}
}
}catch(Exception e) {
System.out.println("外层异常处理");
}
System.out.println("外层正常执行");
}
}
---------------------------------------------------------------------------------------------------------------------------------
打印执行结果:0~4内层正常执行,外层异常处理继续正常执行流程到结束
数据库结果:4条数据正常插入
总结:外部有try Catch、内部无try Catch的时候,外部异常,不能回滚(事物错误)
2.外部无异常,内部有异常
修改Service内层和外层代码如下:
---------------------------------------------------------------------------------------------------------------------------------
package com.sh.springboot.serviceneiceng.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.sh.springboot.bean.Person;
import com.sh.springboot.dao.PersonDao;
import com.sh.springboot.serviceneiceng.ServiceNeiCeng;
/**
* Created by sh on 18/4/28.
*/
@Service
publicclassServiceNeiCengImpl implements ServiceNeiCeng {
@Autowired
PersonDaopersondao;
@Transactional
publicvoid insertNeiCeng(intid, String name) {
Personperson= newPerson();
person.setId(id);
person.setName(name);
persondao.insertPerson(person);
if (id == 4) {
inti = 2 / 0;// 此处会产生异常
}
System.out.println(id + "内层正常执行");
}
}
---------------------------------------------------------------------------------------------------------------------------------
package com.sh.springboot.servicewaiceng.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.sh.springboot.serviceneiceng.ServiceNeiCeng;
import com.sh.springboot.servicewaiceng.ServiceWaiCeng;
/**
* Created by sh on 18/4/28.
*/
@Component
publicclassServiceWaiCengImpl implements ServiceWaiCeng {
@Autowired
private ServiceNeiCeng snc;
@Transactional
publicvoid insertWaiCeng() {
try {
for (intj = 0; j < 8; j++) {
snc.insertNeiCeng(j, j + "姓名");
// if(j == 4) {
// inti = 2 / 0;// 此处会产生异常
// }
}
}catch(Exception e) {
System.out.println("外层异常处理");
}
System.out.println("外层正常执行");
}
}
---------------------------------------------------------------------------------------------------------------------------------
打印执行结果:0~3内层正常打印执行
数据库结果:无数据,全部回滚
总结:外部有try Catch、内部无try Catch的时候,内部异常,全部回滚
内外都有异常,由1和2推理得结果也是事物失败。
四、外层无Try Catch,内层有Try Catch
1.外部有异常,内部无异常
修改Service内层和外层代码如下:
---------------------------------------------------------------------------------------------------------------------------------
package com.sh.springboot.serviceneiceng.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.sh.springboot.bean.Person;
import com.sh.springboot.dao.PersonDao;
import com.sh.springboot.serviceneiceng.ServiceNeiCeng;
/**
* Created by sh on 18/4/28.
*/
@Service
publicclassServiceNeiCengImpl implements ServiceNeiCeng {
@Autowired
PersonDaopersondao;
@Transactional
publicvoid insertNeiCeng(intid, String name) {
try {
Personperson= newPerson();
person.setId(id);
person.setName(name);
persondao.insertPerson(person);
// if(id == 4) {
// inti = 2 / 0;// 此处会产生异常
// }
}catch(Exception e) {
System.out.println(id + "内部异常日志处理");
}
System.out.println(id + "内层正常执行");
}
}
---------------------------------------------------------------------------------------------------------------------------------
package com.sh.springboot.servicewaiceng.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.sh.springboot.serviceneiceng.ServiceNeiCeng;
import com.sh.springboot.servicewaiceng.ServiceWaiCeng;
/**
* Created by sh on 18/4/28.
*/
@Component
publicclassServiceWaiCengImpl implements ServiceWaiCeng {
@Autowired
private ServiceNeiCeng snc;
@Transactional
publicvoid insertWaiCeng() {
for (intj = 0; j < 8; j++) {
snc.insertNeiCeng(j, j + "姓名");
if (j == 4) {
inti = 2 / 0;// 此处会产生异常
}
}
System.out.println("外层正常执行");
}
}
---------------------------------------------------------------------------------------------------------------------------------
打印执行结果:0~4内层打印正常,外层不打印
数据库结果:
总结:外部无try Catch、内部有try Catch的时候,外部异常,全部回滚
2.外部无异常,内部有异常
修改Service内层和外层代码如下:
---------------------------------------------------------------------------------------------------------------------------------
package com.sh.springboot.serviceneiceng.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.sh.springboot.bean.Person;
import com.sh.springboot.dao.PersonDao;
import com.sh.springboot.serviceneiceng.ServiceNeiCeng;
/**
* Created by sh on 18/4/28.
*/
@Service
publicclassServiceNeiCengImpl implements ServiceNeiCeng {
@Autowired
PersonDaopersondao;
@Transactional
publicvoid insertNeiCeng(intid, String name) {
try {
Personperson= newPerson();
person.setId(id);
person.setName(name);
persondao.insertPerson(person);
if (id == 4) {
inti = 2 / 0;// 此处会产生异常
}
}catch(Exception e) {
System.out.println(id + "内部异常日志处理");
}
System.out.println(id + "内层正常执行");
}
}
---------------------------------------------------------------------------------------------------------------------------------
package com.sh.springboot.servicewaiceng.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.sh.springboot.serviceneiceng.ServiceNeiCeng;
import com.sh.springboot.servicewaiceng.ServiceWaiCeng;
/**
* Created by sh on 18/4/28.
*/
@Component
publicclassServiceWaiCengImpl implements ServiceWaiCeng {
@Autowired
private ServiceNeiCeng snc;
@Transactional
publicvoid insertWaiCeng() {
for (intj = 0; j < 8; j++) {
snc.insertNeiCeng(j, j + "姓名");
// if(j == 4) {
// inti = 2 / 0;// 此处会产生异常
// }
}
System.out.println("外层正常执行");
}
}
---------------------------------------------------------------------------------------------------------------------------------
打印执行结果: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-