【JavaEE】Spring事务

目录

  • 一、事务简介
  • 二、Spring事务的实现
    • [2.1 事务的操作](#2.1 事务的操作)
    • [2.2 分类](#2.2 分类)
      • [2.2.1 Spring编程式事务](#2.2.1 Spring编程式事务)
      • [2.2.2 Spring 声明式事务 @Transactional](#2.2.2 Spring 声明式事务 @Transactional)
        • [2.2.2.1 @Transactional 详解](#2.2.2.1 @Transactional 详解)
          • [2.2.2.1.1 rollbackFor](#2.2.2.1.1 rollbackFor)
          • [2.2.2.1.2 Isolation](#2.2.2.1.2 Isolation)
          • [2.2.2.1.3 propagation](#2.2.2.1.3 propagation)

一、事务简介

事务:事务是⼀组操作的集合,是⼀个不可分割的操作。事务会把所有的操作作为⼀个整体,⼀起操作。所以这组操作要么同时成功,要么同时失败。

二、Spring事务的实现

2.1 事务的操作

事务的操作主要有三步:

  1. 开启事start transaction / begin (⼀组操作前开启事务)
  2. 提交事务: commit (这组操作全部成功,提交事务)
  3. 回滚事务: rollback (这组操作中间任何⼀个操作出现异常,回滚事务)

2.2 分类

Spring 中的事务操作分为两类:

  1. 编程式事务(⼿动写代码操作事务)
  2. 声明式事务(利⽤注解⾃动开启和提交事务)

2.2.1 Spring编程式事务

SpringBoot 内置了两个对象:

  1. DataSourceTransactionManager 事务管理器。⽤来获取事务(开启事务),提交或回滚事务
  2. TransactionDefinition 是事务的属性,在获取事务的时候需要将 TransactionDefinition 传递进去从⽽获得⼀个事务 TransactionStatus

示例:

java 复制代码
package com.example.springtransdemo.controller;


import com.example.springtransdemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/user")
@RestController
public class UserController {
      @Autowired
      private UserService userService;
      //事务属性
      @Autowired
      private TransactionDefinition definition;
      //事务管理器
      @Autowired
      private DataSourceTransactionManager transactionManager;
      @RequestMapping("/registry")
      public String registry(String name,String password) {
       //开启事务
       TransactionStatus transaction = transactionManager.getTransaction(definition);
       //⽤⼾注册
       userService.registryUser(name, password);
       //提交事务
       transactionManager.commit(transaction);
       //回滚事务
       //transactionManager.rollback(transaction);
       return "注册成功";
      }
}

当我们不提交时可以在数据库中添加字段,回滚后就不会在数据库中添加字段,提交和回滚方法不能在同一个事务中调用。

2.2.2 Spring 声明式事务 @Transactional

使用这个注解需要添加依赖,但是如果已经添加了MyBatis的依赖,那么就包含了下面需要引入的依赖的内容。

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

注解的应用,在需要使用到事务的方法上加上注解,就会自动提交事务状态。当发⽣了没有处理的error和RunTimeException异常(默认情况下)的时候,就会自动回滚。

例如上面的代码就可以改为:

java 复制代码
        @RequestMapping("/registry")
        @Transactional
        public String registry(String name,String password) {
            //⽤⼾注册
            userService.registryUser(name, password);
            return "注册成功";
        }

那么当我们就是要在捕获处理了异常后,还是将事务进行回滚时,我们就可以手动回滚使用TransactionAspectSupport类下使用currentTransactionStatus方法获取状态,使用isRollbackOnly方法回滚。

java 复制代码
 @RequestMapping("/registry")
        @Transactional
        public String registry(String name,String password) {
            //⽤⼾注册
            userService.registryUser(name, password);
            try{
                int a = 10 / 0;
            } catch (Exception e) {
                log.error("错误");
                TransactionAspectSupport.currentTransactionStatus().isRollbackOnly();
            }
            return "注册成功";
        }
2.2.2.1 @Transactional 详解

修饰范围:

  • 修饰类时,就是修饰类中的所用访问修饰限定符为public的方法。
  • 修饰方法时,只能修饰访问修饰限定符为public的方法。

@Transactiona 常见三大属性:

  1. rollbackFor:异常回滚属性。指定能够触发事务回滚的异常类型。可以指定多个异常类型。
  2. Isolation:事务的隔离级别。默认值为 Isolation.DEFAULT。
  3. propagation:事务的传播机制。默认值为 Propagation.REQUIRED 。
2.2.2.1.1 rollbackFor

@Transactional 默认只在遇到运⾏时异常RunTimeException和Error时才会回滚。

例如执行下面的操作的时候,事务不会回滚,数据库中还是会添加数据。

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

但是我们加上属性rollbackFor就会在发生rollbackFor指定的异常的时候回滚。

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

还有与rollbackFor相似作用的属性:

  • rollbackFor :使用class作为值,在发生该异常的时候回滚。
  • rollbackForClassName:使用类名作为值,在发生该异常的时候回滚。
  • noRollbackFor :使用class作为值,在发生该异常的时候不回滚。
  • noRollbackForClassName:使用类名作为值,在发生该异常的时候不回滚。

    当我们同时使用@Transactionsl的noRollbackFor和rollbackFor对同一异常类处理,后使用的会覆盖前面的。例如 @Transactional(rollbackFor = IOException.class, noRollbackFor = IOException.class)生效的是noRollbackFor = IOException.class
2.2.2.1.2 Isolation

Spring事务的隔离级别有以下几种值:

  • DEFAULT:数据库是什么隔离级别,这个方法就还是什么隔离级别。

剩下的都对应MySQL的隔离级别。

  1. 读未提交(READ_UNCOMMITTED):读未提交,也叫未提交读。该隔离级别的事务可以看到其他事务中
    未提交的数据,会有脏读问题。
  2. 读提交(READ_COMMITTED):读已提交,也叫提交读。该隔离级别的事务能读取到已经提交事务的数据,该隔离级别不会有脏读的问题。
  3. 可重复读(REPEATABLE_READ):事务不会读到其他事务对已有数据的修改,即使其他事务已提交。也就可以确保同⼀事务多次查询的结果⼀致,但是其他事务新插⼊的数据,是可以感知到的,这也就引发了幻读问题。
  4. 串⾏化(SERIALIZABLE):序列化,事务最⾼隔离级别。它会强制事务排序,使之不会发⽣冲突,从⽽解
    决了脏读,不可重复读和幻读问题,但因为执⾏效率低,所以真正使⽤的场景并不多。
2.2.2.1.3 propagation

事务的传播机制有以下七种。

我们以A方法调用B方法为例解释:

  1. Propagation.REQUIRED :默认的事务传播级别,如果当前存在事务,则加⼊该事务,如果当前没有事务,则创建⼀个新的事务。如果A方法有事务,B直接就加入,A没有事务B创建一个事务。
  2. Propagation.SUPPORTS :如果当前存在事务,则加⼊该事务。如果当前没有事务,则以⾮事务的⽅式继续运⾏。如果A方法有事务,B直接就加入,A没有事务B也没有事务。
  3. Propagation.MANDATORY :强制性。如果当前存在事务,则加⼊该事务。如果当前没有事务,则抛出异常。如果A方法有事务,B直接就加入,A没有事务抛异常。
  4. Propagation.REQUIRES_NEW :创建⼀个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部⽅法是否开启事务,Propagation.REQUIRES_NEW 修饰的内部⽅法都会新开启⾃⼰的事务,且开启的事务相互独⽴,互不⼲扰。如果A方法有事务,B创建一个事务,两个事务互不影响,A没有事务,B也会创建一个事务。
  5. Propagation.NOT_SUPPORTED :以⾮事务⽅式运⾏,如果当前存在事务,则把当前事务挂起(不⽤)。如果A方法有事务,B创建一个事务,使用B创建的事务,A没有事务B也没有。
  6. Propagation.NEVER :以⾮事务⽅式运⾏,如果当前存在事务,则抛出异常。如果A方法有事务,抛异常,A没有事务B也没有。
  7. Propagation.NESTED :如果当前存在事务,则创建⼀个事务作为当前事务的嵌套事务来运⾏。如果当前没有事务,则该取值等价于 PROPAGATION_REQUIRED 。如果A方法有事务,B创建一个事务,A的事务相当于B的父事务,A没有事务,B也会创建一个事务。
传播行为 当前有事务 当前无事务
REQUIRED 加入事务 新建事务
SUPPORTS 加入事务 非事务执行
MANDATORY 加入事务 抛出异常
REQUIRES_NEW 挂起当前事务并新建事务 新建事务
NOT_SUPPORTED 挂起当前事务并以非事务执行 非事务执行
NEVER 抛出异常 非事务执行
NESTED 创建嵌套事务 新建事务
相关推荐
oradh30 分钟前
Oracle XTTS实现跨版本迁移和升级(Oracle 11g单库升级至19C RAC集群)
数据库·oracle·11g升级19c·xtts跨版本迁移和升级
z123456789861 小时前
2026最新两款AI编程工具深度对比实测
java·数据库·ai编程
程序猿DD2 小时前
一个 API Key,统一调用大模型、生图和联网搜索
数据库·网关
TlSfoward3 小时前
抓包代理链路下的 TLS 指纹变化分析 TLSFOWARD抓包工具
数据库·爬虫·网络协议·搜索引擎·php
数智化管理手记3 小时前
账龄分析手工统计易遗漏?自动账龄分析工具怎么搭建
大数据·网络·数据库·人工智能·数据挖掘
LabVIEW开发3 小时前
NI Package Manager安装LabVIEW时InternalServerError错误
网络·数据库·labview·labview知识·labview功能·labview程序
SelectDB3 小时前
PostgreSQL 实时同步到 Apache Doris:一站式 CDC 解决方案
数据库
Database_Cool_4 小时前
AI Agent 长期记忆怎么存?阿里云 PolarDB-X 对接 Mem0 记忆框架实践
数据库·阿里云
会编程的土豆4 小时前
数据库范式
数据库·oracle
L1624764 小时前
MySQL 全环境生产快速安装 + 完整配置手册(整合国产银河麒麟适配 + 主从补充版)
数据库·mysql