事物的传播机制

article/2025/9/21 2:29:07

目录

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事务机制:主要包括声明式事务和编程式事务,此处侧重讲解声明式事务,编程式事务在实际开发中得不到广泛使用,仅供学习参考。

Spring声明式事务让我们从复杂的事务处理中得到解脱。使得我们再也无需要去处理获得连接、关闭连接、事务提交和回滚等这些操作。再也无需要我们在与事务相关的方法中处理大量的try…catch…finally代码。我们在使用Spring声明式事务时,有一个非常重要的概念就是事务属性。事务属性通常由事务的传播行为事务的隔离级别事务的超时值事务只读标志组成。我们在进行事务划分时,需要进行事务定义,也就是配置事务的属性。

 嵌套事务: 一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。

1、事务的传播机制

事务的传播机制定义在TransactionDefinition接口中,我们也可以通过枚举类Propagation类调用,下面我也附上两个类的源码

  • Propagation.REQUIRED:支持当前事务,如果当前没有事务,则新建一个事务,默认使用这种,也是最常见的 。
  • Propagation.SUPPORTS:支持当前事务,如果没有事务,就以非事务(即数据库事物)的方式执行。
  • Propagation.MANDATORY:支持当前事务,如果没有事务,就抛出异常.
  • Propagation.REQUIRES_NEW:新建事务,如果当前存在事务,就把当前事务挂起。
  • Propagation.NOT_SUPPORTED:以非事务的方式执行操作,如果当前存在事务,就把当前事务挂起.
  • Propagation.NEVER:以非事务的方式执行,如果当前存在事务,则会抛出异常.
  • Propagation.NESTED:如果当前事务存在,则执行嵌套事务,否则执行类似REQUIRED的操作.

2、测试

2.1、准备测试方法

  • 开启事务 配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
  • 创建实体类User
package com.example.demo.testspringtransaction;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/**
* @author 
* @since  2021年1月13日 下午3:36:34
* @version 1.0
* 
*  	@Data  :注解在类上;提供类所有属性的 getting 和 setting 方法,此外还提供了equals、canEqual、hashCode、toString 方法
*	@Setter:注解在属性上;为属性提供 setting 方法
*	@Getter:注解在属性上;为属性提供 getting 方法
*	@Log4j :注解在类上;为类提供一个 属性名为log 的 log4j 日志对象
*	@NoArgsConstructor:注解在类上;为类提供一个无参的构造方法
*	@AllArgsConstructor:注解在类上;为类提供一个全参的构造方法
*
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {private String id;private String name;
}
  • 创建service接口UserService1 、UserService2 
package com.example.demo.testspringtransaction;
/**
* @author 
* @since  2021年1月13日 下午3:48:27
* @version 1.0
*
*/
public interface UserService1 {public void save(User user);public void update(User user);}
package com.example.demo.testspringtransaction;
/**
* @author 
* @since  2021年1月13日 下午3:48:27
* @version 1.0
*
*/
public interface UserService2 {public void delete(String id);}
  • 创建service实现类:UserService1Impl 、UserService2Impl
package com.example.demo.testspringtransaction;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;/**
* @author  
* @since  2021年1月13日 下午3:56:02
* @version 1.0
*
*/
@Service
@Transactional(propagation=Propagation.REQUIRED)
public class UserService1Impl implements UserService1 {@Autowiredprivate JdbcTemplate jdbcTemplate;@Autowiredprivate UserService2 userService2;@Overridepublic void save(User user) {String sql = "insert into user values(?,?)";jdbcTemplate.update(sql,new Object[]{user.getId(),user.getName()},new int[]{java.sql.Types.VARCHAR,java.sql.Types.VARCHAR});userService2.delete("002");
//		update(user);
//		throw new RuntimeException("error");}@Overridepublic void update(User user) {String sql = "update user set name = ? where id=?";jdbcTemplate.update(sql, new Object[]{user.getName(),user.getId()},new int[]{java.sql.Types.VARCHAR,java.sql.Types.VARCHAR});}}
package com.example.demo.testspringtransaction;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;/**
* @author 
* @since  2021年1月13日 下午3:56:02
* @version 1.0
*
*/
@Service
@Transactional(propagation=Propagation.REQUIRED)
public class UserService2Impl implements UserService2 {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic void delete(String id) {String sql = "delete from user where id=?";jdbcTemplate.update(sql, id);}
}
  • 创建Configuration类,用于创建DataSource实现
package com.example.demo.testspringtransaction;import java.sql.SQLException;import javax.sql.DataSource;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;@Configuration
@ComponentScan(basePackages={"com.example.demo.testspringtransaction"})// 扫描UserService1实现类所在的包路径
@ImportResource(locations={"classpath:beans.xml"})// 添加事务管理
public class JdbcConfig {@Beanpublic JdbcTemplate jdbcTemplate(DataSource dataSource){return new JdbcTemplate(dataSource);}@Beanpublic DataSourceTransactionManager transactionManager(DataSource dataSource){return new DataSourceTransactionManager(dataSource);}@Beanpublic DataSource dataSource(){try {return new SimpleDriverDataSource(new com.mysql.jdbc.Driver(), "jdbc:mysql://localhost:3306/springboot", "root", "123456");} catch (SQLException e) {e.printStackTrace();}return null;}
}
  • 测试类
package com.example.demo.testspringtransaction;import org.springframework.context.annotation.AnnotationConfigApplicationContext;/**
* @author 
* @since  2021年1月13日 下午4:07:42
* @version 1.0
*
*/
public class Test {public static void main(String[] args) {AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(JdbcConfig.class);UserService1 userService1 = ac.getBean(UserService1.class);User user = new User("001","唐僧");userService1.save(user);}}

2.2、事务传播机制的测试

2.2.1、REQUIRED

 定义:如果有事务则加入事务,如果没有事务,则创建一个新的(默认值)。

 注意事项:当两个方法的传播机制都是REQUIRED时,如果一旦发生回滚,两个方法都会回滚。

测试点1:将UserService1Impl和BlogService2Impl的事务传播机制都修改为@Transactional(propagation=Propagation.REQUIRED)

测试点2:将UserService1Impl事务传播机制修改为@Transactional(propagation=Propagation.NOT_SUPPORTED),UserService2Impl的仍为@Transactional(propagation=Propagation.REQUIRED)

总结:

        当UserService1Impl提供事务的时候,UserService2Impl的方法执行使用当前已有事务,不再新建事务;

        当UserService1Impl不创建事务的时候,UserService2Impl的方法执行发现没有事务可用,自己新建事务;

2.2.2、NOT_SUPPORTED

定义:不为当前方法开启事务,相当于没有Spring事务,每条执行语句单独执行,单独提交。

测试点3:将UserService1Impl和BlogService2Impl的事务传播机制都修改为:@Transactional(propagation=Propagation.NOT_SUPPORTED)

总结:

        NOT_SUPPORTED相当于没有Spring事务,每条执行语句单独执行,单独提交。 

2.2.3、REQUIRES_NEW

定义:不管是否存在事务,都创建一个新的事务,原来的方法挂起,新的方法执行完毕后,继续执行老的事务。 老事务报错,老失误回滚,并不影响新事务的提交。

测试点4将UserService1Impl事务传播机制修改为@Transactional(propagation=Propagation.REQUIRED),BlogService2Impl的改为@Transactional(propagation=Propagation.REQUIRES_NEW)

总结:

        REQUIRES_NEW为当前方法创建一个新的事务,并且当前事务先提交,然后再提交老的事务。 

2.2.4、MANDATORY

定义必须在一个已有的事务中执行,否则报错。报错时,前一个方法中的非事务处理,不回滚。

测试点5:将UserService1Impl事务传播机制修改为@Transactional(propagation=Propagation.NOT_SUPPORTED),UserService2Impl的改为@Transactional(propagation=Propagation.MANDATORY),查看是否报错。

总结:    

        MANDATORY必须在已有事务下被调用,否则报错。

        NOT_SUPPORTED执行数据库层面的事务操作,故当前测试中,insert方法成功执行,delete方法的抛错并不影响insert方法的执行。

2.2.5、NEVER

定义:必须在一个没有的事务中执行,否则报错。

测试点6将UserService1Impl事务传播机制修改为@Transactional(propagation=Propagation.REQUIRED),UserService2Impl的仍为@Transactional(propagation=Propagation.NEVER),查看是否报错。

总结:

        NEVER必须在没有事务的方法中执行,否则报错;

        save方法开启一个事务,还没来及提交发现delete方法报错,只能回滚事务。

2.2.6、SUPPORTS

定义:是否使用事务取决于调用方法是否有事务,如果有则直接用,如果没有则不使用事务。

测试点7将UserService1Impl事务传播机制修改为@Transactional(propagation=Propagation.REQUIRED),UserService2Impl的仍为@Transactional(propagation=Propagation.SUPPORTS)

测试点8将UserService1Impl事务传播机制修改为@Transactional(propagation=Propagation.NOT_SUPPORTED),UserService2Impl的仍为@Transactional(propagation=Propagation.SUPPORTS)

  总结:

        SUPPORTS类型的事务传播机制,是否使用事务取决于调用方法是否有事务,如果有则直接用,如果没有则不使用事务

2.2.7、NESTED

定义:如果当前存在事务,则在嵌套事务内执行(当前事务回滚,嵌套事务也回滚;嵌套事务回滚,不影响当前事务)。如果当前没有事务,则执行与REQUIRED类似的操作。

测试点9将UserService1Impl事务传播机制修改为@Transactional(propagation=Propagation.REQUIRED),UserService2Impl 改为@Transactional(propagation=Propagation.NESTED)

测试点10:将UserService1Impl事务传播机制修改为@Transactional(propagation=Propagation.NOT_SUPPORTED),UserService2Impl 改为@Transactional(propagation=Propagation.NESTED)

总结:

        save方法创建一个事务,则再调用delete方法时,直接在该事务的基础上创建一个嵌套事务,本质上还是同一个事务,做一次提交;

        save方法不创建事务,则调用delete方法时,直接创建一个新的事务,单独提交。

3、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

3、spring事务的五种隔离级别


ISOLATION_DEFAULT:是事务管理器的默认隔离级别,使用数据库默认的隔离级别。另外四个与jdbc的隔离级别 相对应

ISOLATION_READ_UNCOMMITTED:最低的隔离级别,它允许一个事务读取另一个事务未提交的数据,会产生脏读 不可重复读,幻读

ISOLATION_READ_COMMITTED:保证一个事务修改的数据提交后另一个事务才能读取到,可以避免脏读.

ISOLATION_REPEATABLE_READ:数据库就是使用的这种隔离级别,可以避免脏读和不可重复读,但是可能出现 幻读(幻读:一个事务读取完,另一个事务提交了更新,本事务再次读取会 发现前后数据不一致,像产生了幻觉一样,所以叫幻读)

ISOLATION_SERIALIZABLE:花费代价最高也是最可开的事务隔离级别,事务被处理为顺序执行,但是这种隔离 级别会产生锁表,就是一个事务读取之后,另一个事务必须等待这个事务完成, 他才可以进行,第一个事务会将整张表锁起来,一般不会使用这种隔离级别, 性能极低!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


http://chatgpt.dhexx.cn/article/oZhgfNg1.shtml

相关文章

Spring事务传播机制

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

Spring事务传播的7种机制

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

事务的传播机制

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

Spring事务传播机制详解

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

反射原理详谈

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

Java反射的作用与原理

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

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

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

java反射原理-重要

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

java 反射机制原理 简述

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

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

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

Java反射原理与使用

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

Java反射原理简析

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

java反射原理

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

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

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

java反射机制原理详解

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

Java 反射及原理

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

回车、换行、回车换行、硬回车以及软回车

回车、换行、回车换行、硬回车以及软回车 要想一句话说清楚它们之间的关系&#xff0c;不太简单。但认真看完后&#xff0c;会发现它们之间的关系其实也挺简单的。 回车、换行与回车换行 英文缩写对应按键英文全称中文名称解释转义表达式使用平台CRreturnCarriage Return回车…

图解回车和换行的区别

文章目录 1. 定义2. 图解3. 讨论4. 结论 1. 定义 中文英文简写HEXCharacterASCII回车Carriage returnCR0x0D\r13换行Line feedLF0x0A\n10 2. 图解 Win11 Experiment by Pycharm with Python 3.9 print(---)print(Hello World)print(---)# \rprint(Hello \r World)print(---…

不同系统下回车和换行的区别

在计算机还没有出现之前&#xff0c;有一种叫做电传打字机&#xff08;Teletype Model 33&#xff09;的玩意&#xff0c;每秒钟可以打10个字符。但是它有一个问题&#xff0c;就是打完一行换行的时候&#xff0c;要用去0.2秒&#xff0c;正好可以打两个字符。要是在这0.2秒里面…

python回车和换行的区别_回车与换行的区别(转)

add by zhj: 不同操作系统下换行符不同&#xff0c;如下&#xff1a; \n: UNIX \n\r: window \r: MAC OS 我们经常遇到的一个问题就是&#xff0c;Unix/Mac系统下的文件在Windows里打开的话&#xff0c;所有文字会变成一行&#xff1b;而Windows里的文件在Unix/Mac下打开的…