Spring事务和事务传播机制

1.事务

1.1 什么是事务

事务是一组操作的集合,是一个不可分割的操作

事务回把所有操作作为一个整体,一起向数据库提交或者是撤销操作的请求,所以这组操作要么同时成功,要么同时失败

1.2 为什么需要事务

2. Spring 中事务的视线

2.1 初步了解

开启事务(获取事务)

提交事务

回滚事务

Spring中内置了两个对象

  1. DataSourceTranscationMapper 事务管理器,用来获取事务(开启事务)提交或回滚事务

  2. TransactionDefintion 是事务的属性,在获取事务的时候需要将TransactionDefiniton 船体从而获取一个事务 TranscationStatus

数据库中成功添加

改为

复制代码
dataSourceTransactionManager.rollback(transactionStatus);

数据可并没有新增数据

2.2 Spring 声明式事务 @Transctional

添加依赖

复制代码
<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-tx</artifactId>
</dependency>

修改程序使之异常

@Transactional 作用:可以用来修饰方法或类

修饰方法时:只修饰public方法时才生效

修饰类时:对修饰的类中所有的public方法都生效

方法类被修饰时,在目标方法执行开始之前,会自动开启事务,方法执行结束之后,自动提交事务

如果发执行过程中,出现异常,且异常未被捕获,就进行事务回滚操作

如果异常被程序捕获,方法就被认为是成功执行,依然会提交事务

虽然程序错误了,但由于异常被不活了,所以事务依然得到了提交

如果想要事务回滚,有两种方法:

1.重新抛出一次

  1. 手动回滚事务

3. @Transactional 详解

@transactionsal 注解中的三个常见属性

  1. rollbackFor:异常回滚属性,指定能够触发事务回滚的异常类型,可以指定多个类型

  2. Isolation:事务的隔离级别,默认为 Isolation.DEFAULT

  3. propagation:事务的传播机制,默认为Propagation.REQUIED

3.1 rollBackFor

@transactional默认只在遇到运行时异常和Error时才会回滚

java 复制代码
@Transactional
@RequestMapping("/r2")
public String r2(String name,String password) throws IOException {
   //⽤⼾注册
   userService.registryUser(name,password);
   log.info("⽤⼾数据插⼊成功");
   if (true){
   throw new IOException();
   }
   return "r2";
}

虽然程序抛出了异常,但是事务依然进行了提交

如果需要所有的异常都回滚,需要配置 @treanscational 注解中的rollbackFor属性

java 复制代码
@Transactional(rollbackFor = Exception.class)
@RequestMapping("/r2")
public String r2(String name,String password) throws IOException {
   // ⽤⼾注册
   userService.registryUser(name,password);
   log.info("⽤⼾数据插⼊成功");
   if (true){
   throw new IOException();
   }
   return "r2";
}

结论:

在Spring的事务管理中,默认只在遇到运行时异常RuntimeException和Error时才会回滚

如果需要回滚指定类型的异常,可以通过rollbackFor属性来指定

3.2 事务隔离级别

3.2.1 Spring 事务隔离级别

Spring 中的事务隔离级别可以通过 @Transactional 中的 isolation属性进行设置

java 复制代码
@Transactional(isolation = Isolation.READ_COMMITTED)
@RequestMapping("/r3")
public String r3(String name,String password) throws IOException {
   //... 代码省略
   return "r3";
}

3.3 Spring 事务传播机制

事务传播机制:多个事务方法存在调用关系时,事务是如何在这些方法间进行传播的

3.3.1 事务的传播机制有哪些

3.3.2 Spring 事务传播机制使用和各种场景延时

重点关注 REQUIRED(默认)和 REQUIRES_NEW

REQUIRED

java 复制代码
@RequestMapping("/propaga")
@RestController
public class PropagationController {
   @Autowired
   private UserService userService;

   @Autowired
   private LogService logService;

   @Transactional(propagation = Propagation.REQUIRED)
   @RequestMapping("/p1")
   public String r3(String name,String password){
      //⽤⼾注册 
      userService.registryUser(name,password);
      //记录操作⽇志
      logService.insertLog(name,"⽤⼾注册");
      return "r3";
  }
} 

对应的UserService和LogService都添加上 Propagation. REQUIRED)

java 复制代码
@Slf4j
@Service
public class UserService {
   @Autowired
   private UserInfoMapper userInfoMapper;

   @Transactional(propagation = Propagation.REQUIRED)
   public void registryUser(String name,String password){
   //插⼊⽤⼾信息
   userInfoMapper.insert(name,password);
   }
}
java 复制代码
@Slf4j
@Service
public class LogService {
   @Autowired
   private LogInfoMapper logInfoMapper;

   @Transactional(propagation = Propagation.REQUIRED)
   public void insertLog(String name,String op){
      int a=10/0;
      //记录⽤⼾操作 
      logInfoMapper.insertLog(name,"⽤⼾注册");
   }
}
   

运行程序,发现数据库没有插入任何数据

流程描述:

  1. p1方法开始事务

  2. 用户注册,出入一条数据(执行成功)

  3. 记录操作日志,插入一条数据(出现异常)

  4. 事务回滚,因为共用同一个事务,数据都回滚了

REQUIRES_NEW

将上述UserService 和LogService中相关⽅法事务传播机制改为REQUIRES_NEW

运行程序,用户数据插入成功,日志数据插入失败

NEVER(不支持当前事务,抛异常)

修改UserService中对应⽅法的事务传播机制为NEVER

程序执行报错,没有数据插入

NESTED(嵌套事务)

将上述UserService 和LogService中相关⽅法事务传播机制改为NESTED

运行程序,没有任何数据输入

流程描述

  1. Controller 中的p1 开始事务

  2. UserService 用户注册,出入一条数据

  3. LogService 记录操作日志,插入一条数据(出现异常)

  4. 由于是嵌套事务,LogService出现异常,全部回滚

NESTED和REQUIRED有什么区别?

java 复制代码
@Service
public class LogService {
   @Autowired
   private LogInfoMapper logInfoMapper;

   @Transactional(propagation = Propagation.NESTED)
   public void insertLog(String name,String op){
      try {
      int a=10/0;
      } catch (Exception e){
      //回滚当前事务
      TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
   }

   //记录⽤⼾操作
   logInfoMapper.insertLog(name,"⽤⼾注册");
}

重新运行程序,发现用户表数据添加成功,日志表添加失败

LogService 中的事务已经回滚,但是嵌套事务不会回滚嵌套之前的事务,也就是说嵌套事务可以实现部分回滚

REQUIRED 如果回滚就是回滚所有事务,不能实现部分事务回滚


整个事务如果全部执行成功,二者的结果是一样的.

如果事务⼀部分执行成功,REQUIRED加⼊事务会导致整个事务全部回滚.NESTED嵌套事务可以实 现局部回滚,不会影响上⼀个方法中执行的结果.

4. 总结

  1. Spring中使用事务,有两种方式,编程式事务和声明式事务,其中声明式事务使用较多,在方法上添加 @Transactional 就可以实现

  2. 可以设置事务的隔离级别(isolation)

  3. 可以设置事务的传播机制(propagation)

相关推荐
量子-Alex15 小时前
【大模型智能体】A practical guide to building agents
大数据·数据库·人工智能
Chase_______15 小时前
【Java基础】5 / 2 为什么等于 2?整数除法、取余和 floorMod 一次讲清
java·开发语言
fish_xk15 小时前
c++11(二)
java·前端·c++
闪电悠米15 小时前
黑马点评-优惠券秒杀-01_redis_global_id
数据库·redis·缓存
星空15 小时前
跨域请求测试
java·java-ee
宠友信息15 小时前
友猫社区Vue与Spring Boot多端社交平台源码架构
java·vue.js·spring boot·架构
牧羊狼的狼15 小时前
MySQL 提升SQL查询性能的全套实战优化方法
数据库·sql·mysql
love8888_cnsd15 小时前
Git & Linux 速查表
java·linux·git·后端·elasticsearch
weixin_4896900215 小时前
企业微信 PC 端本地数据库结构中的巧妙设计
数据库·oracle·企业微信