Spring中的事务传播机制

article/2025/9/21 2:03:54

目录

前言

1、Spring(Spring Boot)实现事务

1.1、通过代码的方式手动实现事务

 1.2、通过注解@Transactional的方式实现声明式事务

 1.2.1、实现:

 1.2.2、程序中有try-catch时,程序发生异常事务不会回滚

 解决方案一:将异常抛出去

 解决方案二:使用代码手动回滚事务

1.2.3、@Transactional参数说明

1.2.4、@Transactional工作原理

2、事务隔离级别

2.1、事务特性

2.2、Spring中设置事务隔离级别

2.2.1、MySQL中事务隔离级别(4种)

2.2.2、Spring事务隔离级别(5种)

3、Spring事务传播机制

3.1、事务传播机制是什么

3.2、为什么需要事务传播机制

 3.3、事务传播机制有哪些

3.4、事务传播的分类 

3.5、Spring事务传播机制使用场景演示

3.5.1、支持当前事务(REQUIRED)

3.5.2、不支持当前事务(REQUIRES_NEW)

3.5.3、嵌套事务(NESTED)

3.6、嵌套事务和加入事务有什么区别?


前言

        为什么需要事务呢?首先需要了解什么是事务,事务就是一组操作封装成一个单元,执行时要么全部成功,要么全部失败~

        就好比,你给我转账,你那边的金额减少了,我这边突然出故障了,钱就凭空没了,你当然是第一个不乐意呀~  所以需要事务,当我这边失败时,事务回滚,你那边的金额就会回到转账前的金额~


1、Spring(Spring Boot)实现事务

1.1、通过代码的方式手动实现事务

Spring手动操作事务就和MySQL操作事务类似,包括三个步骤:

  • 开启事务
  • 提交事务
  • 回滚事务

SpringBoot内置了两个对象:

  • DataSourceTransactionManager用来获取事务(开启事务)、提交事务或回滚事务
  • TransactionDefinition是事务的特性,获取事务时,需要将TransactionDefinition传递进去从而获取一个事务TransactionStatus

代码:

package com.example.demo.controller;import com.example.demo.entity.Userinfo;
import com.example.demo.service.UserService;
import org.apache.catalina.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.time.LocalDateTime;/*** Created with IntelliJ IDEA.* Description:* User:龙宝* Date:2023-03-30* Time:17:07*/
@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate DataSourceTransactionManager transactionManager;@Autowiredprivate TransactionDefinition transactionDefinition;@RequestMapping("/add")public int add(Userinfo userinfo) {//非空校验if(userinfo == null || !StringUtils.hasLength(userinfo.getUsername())|| !StringUtils.hasLength(userinfo.getPassword())) {return 0;}//1、开启事务TransactionStatus transactionStatus = transactionManager.getTransaction(transactionDefinition);int result = userService.add(userinfo);System.out.println("添加:" +result);//2、回滚事务
//        transactionManager.rollback(transactionStatus);//3、提交事务transactionManager.commit(transactionStatus);return result;}}

 1.2、通过注解@Transactional的方式实现声明式事务

@Transactional的特点:

  • 可以添加在类上或方法上。修饰方法时,只能应用到public方法上,否则不生效;修饰类时,表明注解对该类中的所有的public方法都生效
  • 在方法执行前自动开启事务,在方法执行完(无任何异常)自动提交事务,当方法在执行期间出现异常,将自动回滚事务

 1.2.1、实现:

代码;

    @RequestMapping("/add")@Transactional   //声明式事务(自动提交)public Integer add(Userinfo userinfo) {//非空校验if(userinfo == null || !StringUtils.hasLength(userinfo.getUsername()) || !StringUtils.hasLength(userinfo.getPassword())) {return 0;}int result = userService.add(userinfo);System.out.println("添加成功!" + result);return  result;}

 1.2.2、程序中有try-catch时,程序发生异常事务不会回滚

添加一个异常; 

程序启动,前端:

 数据库:

 自动回滚

 但此时,我们如果将这个异常捕捉掉,事务就不会回滚了~

程序启动,前端:

 

数据库:

不会回滚~

 解决方案一:将异常抛出去

 解决方案二:使用代码手动回滚事务

1.2.3、@Transactional参数说明

参数作用
value当配置了多个事务管理器时,可以使用该属性指定选择哪个事务管理器
transactionManager  当配置了多个事务管理器时,可以使用该属性指定选择哪个事务管理器
propagation事务传播行为【事务传播机制是,下文中有详解】
isolation事务的隔离级别,默认值为Isolation.DEFAULT
timeout事务的超时时间,默认值为-1【无时间限制】。如果超过该时长但事务还没有完成,则自动进行回滚事务
readOnly指定事务是否为只读事务,默认值为false;为了忽略那些不需要事务的方法,比如读取数据可以设置read-only为true
rollbackFor用户指定能够触发事务回滚的异常类型,可以指定多个异常类型
rollbackForClassName用于指定能够触发事务回滚的异常类型,可以指定多个异常类型
noRollbackFor抛出指定的异常类型,不回滚事务,也可以指定多个异常类型
noRollbackForClassName抛出指定的异常类型,不回滚事务,也可以指定多个异常类型

1.2.4、@Transactional工作原理

        @Transactional是基于AOP实现的,AOP是使用动态代理实现的。如果目标对象实现了接口,默认情况下会采用JDK的动态代理,如果目标对象没有实现了接口,会使用CGLIB动态代理

        @Transactional在开始执行业务之前,通过代理先开启事务,在执行之后再提交事务。如果中途遇到异常,则回滚事务

@Transactional实现思路:


2、事务隔离级别

2.1、事务特性

4大特性:原子性、持久性、一致性、隔离性~

具体这篇文章下有详细说明:http://t.csdn.cn/fIugI

2.2、Spring中设置事务隔离级别

2.2.1、MySQL中事务隔离级别(4种)

这篇文章中有详细说明:http://t.csdn.cn/fIugI

2.2.2、Spring事务隔离级别(5种)

Spring事务隔离级别,4种和MySQL一致,另外多了一种:

Isolation.DEFAULT:以连接的数据库的隔离级别为主

Spring中如何设置事务隔离级别:


3、Spring事务传播机制

3.1、事务传播机制是什么

        Spring事务中传播机制定义了多个包含了事务的方法,相互调用时,事务是如何在这些方法间进行传递的

3.2、为什么需要事务传播机制

        事务隔离级别是保证多个并发事务执行的可控性的(稳定性),而事务传播机制是保证一个事务在多个调用方法间的可控性(稳定性)

        事务隔离解决的是多个事务同时调用一个数据库的问题,如图:

事务传播机制解决的是一个事务在多个节点(方法)中的传递问题,如下:

 3.3、事务传播机制有哪些

Spring事务的传播机制有以下7种:

  • Propagation.REQUIRED:默认的事务传播机制,他表示如果当前存在事务,则加入事务;如果当前没有事务,则创建一个新的事务
  • Propagation.SUPPORTS:如果当前存在事务,则加入事务;如果当前没有事务,则以非事务的方式继续运行
  • Propagation.MANDATORY:(mandatory强制性)如果单前存在事务,则加入事务;如果当前没有事务,则抛出异常
  • Propagation.REQUIRES_NEW:表示创建一个新的事务,如果对当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW修饰的内部方法会新开启自己的事务,且启动的事务互相独立,互不干扰
  • Propagation.NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起
  • Propagation.NEVER:以非事务方式运行,如果当前存在事务,则把当前事务挂起
  • Propagation.NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于PROPAGATION_REQUIRED

3.4、事务传播的分类 

事务传播分为3类:

  • 支持当前事务:REQUIRED + SUPPORTS + MANDATORY
  • 不支持当前事务:REQUIRES_NEW  +  NOT_SUPPORTED  +  NEVER
  • 嵌套事务 : NESTED

3.5、Spring事务传播机制使用场景演示

3.5.1、支持当前事务(REQUIRED)

我们先开启事务,然后成功插入一条数据,然后执行日志时,报错,观察结果:

UserController:

@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate LogService logService;@RequestMapping("/add")@Transactional(propagation = Propagation.REQUIRED)public int add(Userinfo userinfo) {//非空校验if(userinfo == null || !StringUtils.hasLength(userinfo.getUsername()) || !StringUtils.hasLength(userinfo.getPassword())) {return 0;}//插入数据int result = userService.add(userinfo);//插入日志logService.saveLog("日志内容~");return result;}
}

UserService:

@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public int add(Userinfo userinfo) {return userMapper.add(userinfo);}
}

LogService:

@Service
public class LogService {@Transactional(propagation = Propagation.REQUIRED)public void saveLog(String content) {int i= 1/0;System.out.println(content);}
}

 程序运行:

报异常 ,查看数据库,看事务是否回滚:

回滚了~ 

  • UserService中的保存方法正常执行完成
  • LogService保存日志程序报错,应为使用的是Controller中的事务,所以整个事务也会回滚
  • 数据库中没有插入数据,也就是步骤1中的用户插入方法也回滚了

3.5.2、不支持当前事务(REQUIRES_NEW)

        上述的UserController代码中将事务的传播机制更改为REQUIRES_NEW,将LogService中添加日志的方法前的事务传播机制更改为REQUIRES_NEW,代码更改:

@Service
public class LogService {@Transactional(propagation = Propagation.REQUIRES_NEW)public void saveLog(String content) {try {int i = 1 / 0;} catch (Exception e) {//手动回滚当前事务TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}System.out.println(content);}
}

程序执行:

前端:

 

查看数据库:

 Userinfo表中成功插入数据,Log执行失败,但不影响UserController中的事务

3.5.3、嵌套事务(NESTED)

UserController:

@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate LogService logService;@RequestMapping("/add")@Transactional(propagation = Propagation.NESTED)public int add(Userinfo userinfo) {//非空校验if(userinfo == null || !StringUtils.hasLength(userinfo.getUsername()) || !StringUtils.hasLength(userinfo.getPassword())) {return 0;}//插入数据int result1 = userService.add(userinfo);int result2 = userService.insert();return result1 + result2;}
}

UserSevice:

@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public int add(Userinfo userinfo) {return userMapper.add(userinfo);}@Transactional(propagation = Propagation.NESTED)public int  insert() {Userinfo userinfo = new Userinfo();userinfo.setUsername("李四");userinfo.setPassword("789");int ret = userMapper.add(userinfo);int i = 1/0;return ret;}
}

程序启动:

 数据库:

 结果:无数据添加

        因为是嵌套事务,所以日志添加回滚之后,往上找调用它的方法和事务回滚了用户添加,所以用户数据添加都失败了

3.6、嵌套事务和加入事务有什么区别?

  • 嵌套事务,可以实现部分事务回滚,也就是说回滚时,一直往上找调用它的方法和事务回滚,而不会回滚嵌套之前的事务
  • 加入事务,相当我已经成了他的一部分,回滚时,整个一起回滚
  • 整个事务如果全部执行成功,二者的结果是一样的

好啦,本期到这里就结束咯,我们下期见~


http://chatgpt.dhexx.cn/article/7q7ChiGn.shtml

相关文章

事务的7种传播机制和演示

文章目录 一、事务的传播机制1.1、nested 事务的几点说明: 二、示例2.1、前言:2.2、准备测试方法1)创建beans.xml,开启事务2)创建实体类和表(表创建读者可自定义创建)3)创建service接…

事务传播行为

原文作者:https://blog.csdn.net/soonfly/article/details/70305683 事务传播行为 什么叫事务传播行为?听起来挺高端的,其实很简单。 即然是传播,那么至少有两个东西,才可以发生传播。单体不存在传播这个行为。 事务传…

[事务] 事务的传播机制

前言: Spring的事务,也就是数据库的事务操作,符合ACID标准,也具有标准的事务隔离级别。 但是Spring事务有自己的特点,也就是事务传播机制。 所谓事务传播机制,也就是在事务在多个方法的调用中是如何传递的&…

事物的传播机制

目录 1、事务的传播机制 2、测试 2.1、准备测试方法 2.2、事务传播机制的测试 2.2.1、REQUIRED 2.2.2、NOT_SUPPORTED 2.2.3、REQUIRES_NEW 2.2.4、MANDATORY 2.2.5、NEVER 2.2.6、SUPPORTS 2.2.7、NESTED 事务传播机制:就是事务在多个方法的调用中是如何…

Spring事务传播机制

目录 一、事务在Spring中是如何运作的 1.1 开启事务(DataSourceTransactionManager.doBegin) 二、Spring的事务传播机制 2.1 子事务的传播机制为REQUIRED 2.2 子事务的传播机制为REQUIRES_NEW 2.3 子事务的传播机制为NESTED 当我们在使用Spring所提供的事务功能时&#x…

Spring事务传播的7种机制

Spring 事务传播机制包含以下 7 种: 1. Propagation.REQUIRED:默认的事务传播级别,它表示如果当前存在事务,则加入该事务;如果 当前没有事务,则创建一个新的事务。 2. Propagation.SUPPORTS:如果…

事务的传播机制

目录 1.形象说明: 2.代码演示: 2.1 REQUIRED 2.1.1 验证共用一个事务 2.1.2 验证当前没有事务,就新建一个事务 2.2 SUPPORTS 2.2.1 支持使用当前事务 2.2.2 如果当前事务不存在,则不使用事务 2.3 MANDATORY 2.3.1 支持…

Spring事务传播机制详解

前言: Spring的事务,也就是数据库的事务操作,符合ACID标准,也具有标准的事务隔离级别。 但是Spring事务有自己的特点,也就是事务传播机制。 所谓事务传播机制,也就是在事务在多个方法的调用中是如何传递的&…

反射原理详谈

什么是反射? 反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 Java 语言…

Java反射的作用与原理

Java反射的作用与原理 定义 反射机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。在Java中,只要给定类…

彻底搞懂java反射技术及其原理

概述:反射是java中最强大的技术之一,很多高级框架都用到了反射技术,面试中也是经常问的点,所以搞懂反射非常重要! 文章目录 1.反射是什么?2.反射的底层原理3.三种方式获取Class对象4.反射的优缺点5.反射的应用场景6.反射的常用API 1.反射是什么? java反射机制指…

java反射原理-重要

一,反射是什么(反射是框架设计的灵魂) 1,JAVA反射机制是在运行状态中 对于任意一个类,都能够知道这个类的所有属性和方法; 对于任意一个对象,都能够调用它的任意一个方法和属性; …

java 反射机制原理 简述

什么是反射机制? 1、在运行状态中,对于任意一个类,都能够知道这个类的属性和方法。 2、对于任意一个对象,都能够调用它的任何方法和属性。这种动态获取信息以及动态调用对象的方法的功能称为JAVA的反射。 反射的作用 1、在运行…

java反射如何实现的_Java反射实现原理

Java反射应用十分广泛,例如spring的核心功能控制反转IOC就是通过反射来实现的,本文主要研究一下发射方法调用的实现方式和反射对性能的影响。 如下为Method类中invoke方法,可以看出该方法实际是将反射方法的调用委派给MethodAccessor&#xf…

Java反射原理与使用

当类加载器将类加载进jvm之后,jvm会创建每一个类的元数据对象(Class),这个元数据对象(Class)记录着这类的所有信息,java语言允许通过元数据对象动态的创建对象实例,这种机制就称为java的反射机制,基本上所有框架的底层都用到了反射机制,spring、mybatis、servlet都用到了 1.如…

Java反射原理简析

Java的反射机制允许我们动态的调用某个对象的方法/构造函数,获取某个对象的属性等,而无需在编码时确定调用的对象。这种机制在我们常用的框架中也非常常见。 1.原理简介 类actionClass Class.forName(“ MyClass”); 对象actio…

java反射原理

一、反射机制 在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态(在运行时)获取类的信息以及动态调用对象的方法的功能称为java语言的反射机制。简单来说,就是Java对每一个类和类中的所有成…

Java反射(原理剖析与使用)

一、反射机制是什么 1、Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。 2、Java属于先编译再运行的语言&a…

java反射机制原理详解

Java反射机制是指在运行时动态地获取一个类的信息并能够操作该类的属性和方法的能力。Java反射机制使得程序能够在运行时借助Class类的API来操作自身的属性和方法,从而大大增强了Java的灵活性和可扩展性。本文将详细介绍Java反射机制的原理以及如何使用它。 1、反射…

Java 反射及原理

反射,指的是对于任意一个类,都可以动态的获得它的所有属性和方法,对于任意一个对象都能调用的它的所有属性和方法,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。…