1.try catch 与事务的关系
事务在开发中是一个非常重要的环节,try catch 在一定条件下会让事务失效,回滚失败。下面就用代码来测试一下try catch 与事务的关系。
首先准备一张数据库表,原始数据为空,如下:
然后我们下面的代码都只需要调用一下 learnTryCatch 方法。
1.1 不加try catch正常回滚
看service层代码:
@Service
public class TestMyServiceImpl implements TestMyService {
@Autowired
private TestMyMapper testMyMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public void learnTryCatch() {
TestMy data = getData();
testMyMapper.insert(data);
throw new RuntimeException();
}
private TestMy getData(){
TestMy testMy = new TestMy();
testMy.setName("陆雪琪");
testMy.setNumber(18);
testMy.setTime(LocalDateTime.now());
return testMy;
}
}
执行之后的结果如下图,可见事务正常回滚。
1.2 加try catch,事务不能正常回滚
再来看以下代码:
@Service
public class TestMyServiceImpl implements TestMyService {
@Autowired
private TestMyMapper testMyMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public void learnTryCatch() {
TestMy data = getData();
testMyMapper.insert(data);
try {
data.setId(null);
data.setName("陆雪琪");
testMyMapper.insert(data);
throw new IndexOutOfBoundsException();
}catch (Exception e){
e.printStackTrace();
}
}
private TestMy getData(){
TestMy testMy = new TestMy();
testMy.setName("碧瑶");
testMy.setNumber(18);
testMy.setTime(LocalDateTime.now());
return testMy;
}
}
执行后结果如下图:
可见,在try中抛出了异常,但是整个方法的事务并没有回滚。
1.3 加try catch,发生异常可以回滚
来看下面的代码:
@Service
public class TestMyServiceImpl implements TestMyService {
@Autowired
private TestMyMapper testMyMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public void learnTryCatch() {
TestMy data = getData();
testMyMapper.insert(data);
try {
data.setId(null);
data.setName("崔莺莺");
testMyMapper.insert(data);
throw new IndexOutOfBoundsException();
}catch (NullPointerException e){
e.printStackTrace();
}
}
private TestMy getData(){
TestMy testMy = new TestMy();
testMy.setName("冯小青");
testMy.setNumber(18);
testMy.setTime(LocalDateTime.now());
return testMy;
}
}
这里抛出IndexOutOfBoundsException,但是只捕捉NullPointerException。来看执行结果:
可见整个方法的事务正常回滚了。
1.4 在try中调用加事务的方法
我们先来做一个测试,不加try catch 调用别的插入方法,看代码:
@Service
public class TestMyServiceImpl implements TestMyService {
@Autowired
private TestMyMapper testMyMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public void learnTryCatch() {
TestMy data = getData();
testMyMapper.insert(data);
//调用别的插入数据的方法
this.testTran();
throw new IndexOutOfBoundsException();
}
@Override
public void testTran() {
TestMy data = getData();
data.setName("苏小小");
testMyMapper.insert(data);
}
private TestMy getData() {
TestMy testMy = new TestMy();
testMy.setName("冯小青");
testMy.setNumber(18);
testMy.setTime(LocalDateTime.now());
return testMy;
}
}
结果如下图,没有新插入数据,可见只要是本方法(加了事务注解)调用的方法,事务都会生效。
然后我们试一下在try中调用加事务注解的方法,话不多说,看代码:
@Service
public class TestMyServiceImpl implements TestMyService {
@Autowired
private TestMyMapper testMyMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public void learnTryCatch() {
TestMy data = getData();
testMyMapper.insert(data);
try {
data.setId(null);
data.setName("崔莺莺");
testMyMapper.insert(data);
//调用加事务的方法
this.testTran();
throw new IndexOutOfBoundsException();
}catch (Exception e){
e.printStackTrace();
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void testTran() {
TestMy data = getData();
data.setName("苏小小");
testMyMapper.insert(data);
}
private TestMy getData(){
TestMy testMy = new TestMy();
testMy.setName("冯小青");
testMy.setNumber(18);
testMy.setTime(LocalDateTime.now());
return testMy;
}
}
我们知道,learnTryCatch 这个方法的事务是回滚不了的。因为try中的异常被catch捕获了。那么testTran方法被try中的代码调用,事务能回滚吗?我们执行一下看结果:
从结果可知,冯小青、崔莺莺、苏小小都加上了,说明任何事物都没有生效。
1.5 使用 throws Exception
看代码:
@Service
public class TestMyServiceImpl implements TestMyService {
@Autowired
private TestMyMapper testMyMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public void learnTryCatch() throws Exception{
TestMy data = getData();
testMyMapper.insert(data);
//调用插入方法
this.testTran();
throw new IndexOutOfBoundsException();
}
@Override
@Transactional(rollbackFor = Exception.class)
public void testTran() {
TestMy data = getData();
data.setName("萧炎");
testMyMapper.insert(data);
}
private TestMy getData() {
TestMy testMy = new TestMy();
testMy.setName("柳七月");
testMy.setNumber(18);
testMy.setTime(LocalDateTime.now());
return testMy;
}
}
我们改用throws 异常来处理异常,事务会回滚吗?话不多说看执行结果:
可见事务正常回滚。
1.6 结论
从以上案例可知,当try中的异常被catch捕捉时,所有事务无法回滚,未被catch捕获时事务可以正常回滚。
所以这里告诉我们:
- 1.不要在try中乱抛异常!!!!
- 2.使用事务就throws Exception ,不要 try catch 。
2 try catch 程序执行逻辑
2.1 程序抛出异常继续执行
来看下面的代码:
@Override
@Transactional(rollbackFor = Exception.class)
public void learnTryCatch() {
try {
throw new NullPointerException();
}catch (Exception e){
e.printStackTrace();
}
System.out.println("抛出了异常!!");
}
执行结果:
可见,抛出了异常,还在继续执行代码。
2.2 程序抛出异常终止执行
看代码:
@Override
@Transactional(rollbackFor = Exception.class)
public void learnTryCatch() {
try {
throw new IndexOutOfBoundsException();
}catch (NullPointerException e){
e.printStackTrace();
}
System.out.println("抛出了异常!!");
}
这里catch没有捕捉try中抛出的异常,程序直接终止:
2.3 结论
可知,当try中的异常被catch捕获,则程序会继续执行。若try中的异常未被catch捕获,则程序终止执行。
所以别在try catch 中乱抛异常,不然会很奇怪抛出了异常怎么程序还是执行了。