16-Spring Boot 事务

Spring 事务

  1. 数据库事务是企业应用中最为重要的内容之一。
  2. 事务往往会涉及到注释@Transactional

1. Spring的数据管理器的设计

  1. 在Spring中数据库事务是通过PlatformTransactionManager进行管理的,而能够支持事务的是org.springframework.transaction.support.TransactionTemplate,它是Spring所提供的事务管理器的模板。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//事务管理器
private PlatformTransactionManager transactionManager;
......
@Override
public <T> T execute(TransactionCallback<T> action) throws TransactionException{
// 使用自定义的事务管理器
if(this.transactionManager instanceof CallbackPreferringPlatformTransactionManager){
return ((CallbackPreferringPlatformTransactionManager)this.transactionManager).execute(this,action);
}else{//系统默认管理器
//获取事务状态
TransactionStatus status = this.transactionManager.getTransaction(this);
T result;
try{
//回调接口方法
result = action.doInTransaction(status);
}catch(RuntimeException ex){
//Transactional code threw application exception -> rollback
//回滚异常方法
rollbackOnException(status, ex);
//抛出异常
throw ex;
}catch(Error ex){
//Transactional code threw error -> rollback
//回滚异常方法
rollbackOnException(status, err);
//抛出错误
throw err;
}catch(Throwable ex){
//Transactional code threw unexpected exception -> rollback
//回滚异常方法
rollbackOnException(status, ex);
//抛出无法捕获异常
throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
}
//提交事务
this.transactionManager.commit(status);
//返回结果
return result;
}
}
  1. 事务的创建、提交和回滚是通过PlatformTransactionManager接口来完成。
  2. 当事务产生异常时会回滚事务,在默认的实现中所有的异常都会回滚,可以通过配置去修改在某些异常发生时回滚或者不会滚事务。
  3. 当无异常时,会提交事务。
  4. 多种事务管理器如下

1.1. 数据管理器分类

  1. 可以看到多个数据库管理器,并且支持JTA事务,常用的是DataSourceTransactionManager,集成抽象事务管理器AbstractPlatformTransactionManager,而AbstractPlatformTransactionManager又实现了PlatformTransactionManager。这样Spring就可以如同源码中那样使用PlatformTransactionManager接口的方法,创建、提交或者回滚事务了。
  2. PlatformTransactionManager接口的源码如下:
1
2
3
4
5
6
7
8
public interface PlatformTransactionManager{
//获取事务状态
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
// 提交事务
void commit(TransactionStatus status) throws TransactionException;
//回滚事务
void rollback(TransactionStatus status) throws TransactionException;
}

2. 通过标签来完成Spring的事务回滚

  1. 将所有的对于数据库的操作都放置到一个被@Transactional标记的Service方法中可以全部回滚
1
2
3
4
5
6
7
8
9
10
11
12
@Transactional
public boolean UserRegister(ESysUser entity) {
try {
//插入ESysUser
eSysUserDao.insert(entity);
} catch (Exception e) {
// handle exception 启动回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
log.error(e.getMessage(), e);
return false;
}
}

2.1. 根据异常进行回滚

@Transactional(rollbackFor = { Exception.class})

  1. 没有捕获异常,则会抛出异常,则将doDbStuff1()中的数据库操作进行回滚。
1
2
3
4
5
@Transactional(rollbackFor = { Exception.class })    
public void test() throws Exception {    
     doDbStuff1();    
     doDbStuff2();//假如这个操作数据库的方法会抛出异常,方法doDbStuff1()对数据库的操作会回滚。    
}  
  1. 如果在程序中自已捕获异常未往外抛,如下代码事务不会回滚
1
2
3
4
5
6
7
8
9
@Transactional(rollbackFor = { Exception.class })    
public void test() {    
     try {    
        doDbStuff1();    
        doDbStuff2();//假如这个操作数据库的方法会抛出异常,现在方法doDbStuff1()对数据库的操作  不会回滚。    
     } catch (Exception e) {    
           e.printStackTrace();       
     }    
}
  1. 既要捕获异常,又要回滚
1
2
3
4
5
6
7
8
9
10
11
@Transactional(rollbackFor = { Exception.class })    
public void test() {    
try {    
doDbStuff1();
doDbStuff2();
catch (Exception e) {
e.printStackTrace();
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();//就是这一句了,加上之后,如果doDbStuff2()抛了异常,
return;  
  }    
}

2.2. 回滚部分异常

  1. 使用Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();设置回滚点。
  2. 使用TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);回滚到savePoint。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Transactional(rollbackFor = Exception.class)
@Override
public void saveEntity() throws Exception{
Object savePoint = null;
try {
userDao.saveUser();
//设置回滚点
savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
studentDao.saveStudent(); //执行成功
int a = 10/0; //这里因为除数0会报异常,进入catch块
}catch (Exception e){
System.out.println("异常了=====" + e);
//手工回滚异常
TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);
}
}

3. 参考

  1. 【Java EE】深入Spring数据库事务管理
  2. spring事务回滚:当同时需要在多个数据表插入数据时,一个出错如何实现全部回滚
  3. Spring中抛出异常时,既要要返回错误信息,还要做事务回滚
  4. SpringBoot事务简单操作及手动回滚

16-Spring Boot 事务
https://spricoder.github.io/2022/04/13/Spring-Boot/16-Spring-Boot-%E4%BA%8B%E5%8A%A1/
作者
SpriCoder
发布于
2022年4月13日
许可协议