iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >一文详解Spring事务的实现与本质
  • 641
分享到

一文详解Spring事务的实现与本质

Spring事务实现Spring事务本质Spring事务 2023-05-14 09:05:31 641人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录一、spring事务的基础知识1.脏读、不可重复读、幻读2.事务的隔离级别3.事务的传播机制二、Spring事务的实现方式1.编程式事务2.声明式事务三、Spring事务的本质四

一、Spring事务的基础知识

先回忆下Spring事务的基础知识事务的隔离级别与Spring事务的传播机制。我们知道数据库层面是不支持事务的传播机制的,这个是Spring独有的

1.脏读、不可重复读、幻读

脏读:对于同一条数据在一个事务中多次读取的结果不一致,原因是第二次读取数据时读取的数据被其他未提交的事务修改了,当隔离级别是读未提交时就会有这种问题存在。

不可重复读:对于同一条数据在一个事务中多次读取的结果不一致,原因是第二次读取数据时读取的数据被其他已提交的事务修改了,当隔离级别是读已提交时就会有这种问题存在。

幻读:脏读和不可重复读都是针对一条数据来说的,而我们使用重复读的隔离级别就可以解决脏读和不可重复读的问题了,但是还是会有幻读的问题,那什么是幻读呢?幻读指的是范围查询前后检索结果不一致,比如说事务里第一次查询customer表有10万记录,同一个事务第二次查询时有11万记录,这就是幻读。幻读产生的原因不是事务并发修改导致的(不可),而是查询时有其他事务在做插入,导致了数据在量上出现了变化。

2.事务的隔离级别

Spring支持的事务隔离级别与数据的隔离级别其实没有任何区别都是四种,说隔离级别必须要说事务的四大特性原子性、一致性、隔离性、持久性。需要拿出来说的便是隔离性,事务在支持隔离性时并不是将事务之间直接彻底隔离,而是给我们提供了几个级别来划分隔离的程度,也就是下面四种了。只有串行化才可以做到事务之间的完全隔离,而其他的隔离级别自然就会产生不同的问题了,因为事务之间有交叉。

  • 读未提交:这是最低的隔离级别,相当于事务之间的隔离性基本没有,所以这种隔离级别什么问题都解决不了,使用这种隔离级别会伴随脏读、不可重复读、幻读等问题。
  • 读已提交:同一个事务里读取的数据是其他事务里已经提交的数据,所以不会读取到其他事务未提交的数据,所有不会有脏读的问题,但是还是可能发生不可重复读、幻读的问题。
  • 重复读:同一个事务里支持重复读取,也就是同一个事务里前后读取的某条数据肯定一致(只针对某一条数据而言),但是仍然解决不了幻读的问题,幻读是因为并发插入导致的。重复读只能解决并发修改的问题。
  • 串行化:串行化可以解决隔离性产生的所有问题,但是他的效率特别的低,所有任务都会排队进行处理,在并发系统中效率非常低下。

3.事务的传播机制

事务的传播机制是Spring特有的机制,各个数据库是不支持的,那Spring的传播机制是什么呢,他们有什么作用呢?

  • PROPAGATioN_REQUIRED(默认):如果当前方法没有事务,就创建一个新事务;如果当前方法已经有事务,就加入到当前事务中。
  • PROPAGATION_SUPPORTS:如果当前方法有事务,就加入到当前事务中;如果当前方法没有事务,就以非事务的方式执行。
  • PROPAGATION_MANDATORY:如果当前方法有事务,就加入到当前事务中;如果当前方法没有事务,就抛出异常。
  • PROPAGATION_REQUIRES_NEW:无论当前方法是否有事务,都创建一个新事务;如果当前方法已经有事务,就挂起当前事务。
  • PROPAGATION_NOT_SUPPORTED:以非事务的方式执行当前方法;如果当前方法有事务,就挂起当前事务。
  • PROPAGATION_NEVER:以非事务的方式执行当前方法;如果当前方法有事务,就抛出异常。
  • PROPAGATION_NESTED:在当前事务中创建一个嵌套事务;如果当前方法没有事务,就相当于PROPAGATION_REQUIRED。

二、Spring事务的实现方式

Spring提供了两种事务的支持方式一种常用的声明式事务,所谓声明式事务就是我们直接使用注解声明即可,而无需手动写事务的开启提交和回滚,这种事务的实现方式是aop,AOP底层则是jdk的动态代理和CGLIB的动态代理。另一种支持的事务则是编程式事务,这种实现方式则是直接编写事务代码,底层通过ORM框架调用到数据库实现的事务,编程式事务具有更加灵活的特点,同时Spring为我们提供了两种编程式事务的实现方式,一种是TransactionTemplate,一种是PlatformTransactionManager。他们都能实现编程式事务,不过使用TransactionTemplate无需我们手动提交或者回滚,Spring会根据异常抛出与否进行提交或者回滚。使用PlatformTransactionManager就需要我们自己提交或者回滚了。下面看下他们的实现区别吧

1.编程式事务

使用TransactionTemplate实现编程式事务

下面是使用TransactionTemplate的伪代码,我们可以为TransactionTemplate指明他的隔离级别和传播机制,注意这里并没有配置数据源相关操作,数据源仍需要单独在配置文件中进行声明数据源的类型和驱动类以及其他的数据库访问的账号路径超时时间最大连接等信息。

@Component
public class TestTransactionTemplate {

    
    private TransactionTemplate transactionTemplate;
    
	@Inject
    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
        transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ);
        transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
    }

    public void transferMoney(final String froMaccount, final String toAccount, final double amount) {
        transactionTemplate.execute(new TransactionCallback<Void>() {
            public Void doInTransaction(TransactionStatus status) {
                try {
                    // 执行转账操作,将金额从fromAccount转到toAccount
//                    accountService.transfer(fromAccount, toAccount, amount);
                    // 如果没有发生异常,则提交事务
                    return null;
                } catch (Exception ex) {
                    // 如果发生异常,则回滚事务
                    status.setRollbackOnly();
                    throw new RuntimeException(ex);
                }
            }
        });
    }
}

使用PlatformTransactionManager实现

使用PlatformTransactionManager则必须我们手动进行提交或者回滚,下面是他的伪代码

@Component
public class TestPlatformTransactionManager {

    PlatformTransactionManager transactionManager;

    @Inject
    public void setTransactionManager(PlatformTransactionManager transactionManager){
        this.transactionManager = transactionManager;
    }

    public void transfer(String fromAccount, String toAccount, double amount) {
        DefaultTransactionDefinition txDef = new DefaultTransactionDefinition();
        txDef.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ);
        txDef.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        
        TransactionStatus txStatus = transactionManager.getTransaction(txDef);
        try {
            //执行转账操作,将金额从fromAccount转到toAccount
//            accountService.transfer(fromAccount, toAccount, amount);
            //如果没有发生异常,则提交事务
            transactionManager.commit(txStatus);
        } catch (Exception ex) {
            //如果发生异常,则回滚事务
            transactionManager.rollback(txStatus);
            throw ex;
        }
    }
}

2.声明式事务

声明式事务底层利用AOP的方式对我们的事务对象进行代理,然后通过前后的增强操作实现了事务的管理,其实底层他们还是一样的,使用声明式事务的伪代码如下,我们可以为注解声明需要的各种属性,常用的就是事务的传播机制、隔离级别、超时时间、回滚异常、非回滚异常等。

@Component
public class TestTransactional {

    @Transactional(propagation = Propagation.REQUIRES_NEW //设置传播机制
            ,isolation = Isolation.REPEATABLE_READ //设置隔离级别
            ,readOnly = false //设置是否只读
            ,timeout = 30 //设置数据库连接的超时时间
            ,transactionManager = "defaultTransactionManager" //设置事务管理器,一个工程多个时可以使用该方式
            ,rollbackFor = IllegalArgumentException.class // 指定回滚异常
            ,noRollbackFor = IndexOutOfBoundsException.class) // 指定非回滚异常
    public Boolean transfer(String fromAccount, String toAccount, double amount){

        // 业务操作...

        return Boolean.TRUE;
    }
}

三、Spring事务的本质

Spring虽然提供了多种事务的实现方式,其实最底层都是有一样的。他都必须依赖数据源来对数据库进行访问,根据数据源来进行不同的封装就实现了Spring的不同的事务实现方式。编程式事务是直接获取数据源后进行手动操作,我们使用的PlatformTransactionManager、或者TransactionTemplate都是需要利用数据源来进行操作的。Spring通过数据源来和数据库建立连接,开启连接后我们就可以为这个连接设置他的隔离级别和一些超时信息等。这样就会建立起一个事务了,最底层利用的还是数据库的事务的动作。声明式事务与编程式事务原理都是一致,只不过Spring通过AOP将我们的业务代码进行了代理,产生了一个代理对象,具体使用什么代理技术Spring会根据我们的实现类进行选择使用JDK还是CGLIB。产生的代理对象我们就可以在被Transactional注解修饰的方法的前后添加事务处理的相关代码了,这个代码和使用编程式事务的代码区别不大。所以说Spring事务的本质其实还是利用数据源打开和数据库的连接,在连接上进行事务的操作。Spring根据不同需要又封装了不同的事务实现,底层却都是一致的。

四、Spring中事务常碰到的问题

这里总结两个常见的事务问题事务的回滚和不回滚,以及事务嵌套的场景

1.事务回滚

在不声明回滚异常类时,只要被事务管理的方法发生异常,那么事务就是会回滚的。Spring根据抛出的异常来进行事务回滚。如果我们对异常进行了cath那Spring是无法进行事务回滚的,因为没有异常抛出了。如果想要回滚我们可以手动声明一个自定义异常或者指定的其他异常。这样就可以实现回滚。当然即使抛出了异常也不一定会回滚。这个还需要依赖我们指定的异常回滚类,一般可以为Transactional指明noRollBackFor。通过他可以指明在哪些异常下不回滚。通过rollBackFor指明哪些异常下回滚,需要满足回滚异常时才会去回滚。

那如果把异常catch了,又没有抛出异常我们有没有其他方式进行回滚呢(使用声明式事务时)?其实还有一种方式进行回滚,如下所示:

@Transactional
public void someMethod() {
    
    if (condition) {
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
}

这种操作就是拿到当前事务的状态手动更改为回滚状态,当执行到AOP的后置增强时,就会调用回滚方法,从而达到了回滚的目的。

2.事务嵌套

有没有思考过这个问题:Spring的事务的传播机制到底是做什么用的呢?

其实一般场景下Spring的事务传播机制很少用得到,我们通常都是不显示指定传播机制的,而是使用默认的PROPAGATION_REQUIRED。默认的这个传播机制就是有事务那我就使用你的事务,如果没有事务我就新建一个事务。假如有以下的场景存在,为了方便看就是用a、b命名方法了:

    @Transactional
    public void a(){ 
        //a方法被事务管理了,同时又调用了b这个事务方法
        b();
    }
    
    @Transactional
    public void b(){

​​​​​​​    }

在此时我们不为a、b两个方法声明传播机制时,那a、b两个方法其实是共用一个事务的,因为他们的事务传播机制是PROPAGATION_REQUIRED。这个机制就是有事务就用已经存在的,没有则新建,很显然a方法时开启了一个事务,执行b方法时既然事务以及存在,就使用了a的事务。所以a、b方法其实是共用事务的。回看第一部分Spring中事务的传播机制其实有7种,其实这其中主要就是为了事务嵌套场景下使用的,也就是我们事务中又调用了事务的场景。此时我们就需要关注内层事务到底需要做什么,需不需要和上层事务保持一致的动作,如果不需要我们就可以选择PROPAGATION_REQUIRED_NEW,这样内层事务就是一个全新的事务。此时Spring是通过数据源和数据库新建立了一个连接,从而实现了新的事务开启。

此外在其中传播机制中最后一种需要单独说下:PROPAGATION_NESTED,他是嵌套事务。这个才是真正为嵌套事务使用的传播机制。上面的例子中有内层事务和外层事务其实他的原理还是不同的事务。而PROPAGATION_NESTED嵌套事务的底层却是使用的一个事务实现的嵌套事务。此时上面的代码可以改造如下:

    @Transactional(propagation = Propagation.REQUIRED)
    public void a(){
        //a方法被事务管理了,同时又调用了b这个事务方法
        b();
    }

    @Transactional(propagation = Propagation.NESTED)
    public void b(){

    }

此时b方法就是一个嵌套事务了,Spring的嵌套事务同样底层是依赖于数据库的嵌套事务,在Mysql里支持了一种伪嵌套事务,就是通过在一个事务中保存回滚点savepoint的方式来进行事务嵌套。当事务正常提交时都会提交,当事务异常时我们可以指定事务回滚到指定的回滚点,下面列举一个mysql的回滚例子:假设有一个员工表employees表,对他进行了如下的操作:

START TRANSACTION;
SAVEPOINT sp1;

INSERT INTO employees (id, name, age) VALUES (1, 'Alice', 30);

SAVEPOINT sp2;

INSERT INTO employees (id, name, age) VALUES (3, 'Bob', 25);

SAVEPOINT sp3;

INSERT INTO employees (id, name, age) VALUES (4, 'Charlie', 27);

SAVEPOINT sp4;

INSERT INTO employees (id, name, age) VALUES (5, 'Dave', 29);

ROLLBACK TO sp3;
COMMIT;

上面的例子我们创建了4个回滚点,且我们最后是回滚到了sp3这个savepoint,那就意味着sp3之后的所有操作不会被写入数据库,而sp3之前的所有操作还是会正常入库,这样就实现了事务嵌套场景下的部分回滚机制。Spring事务传播机制中的PROPAGATION_NESTED底层正是利用了Mysql的这一功能进行了事务嵌套场景下的部分回滚。

五、总结

这篇先介绍了事务的基础知识,然后总结了Spring事务的支持方式,分析了他们的原理,最后总结下来就会发现Spring的事务其实全部都是依赖于数据源对数据库的事务操作,若是数据库事务不支持的动作,Spring也是不支持的。Spring事务的支持动作都是依赖于底层数据库事务的封装,包括了嵌套事务的场景,希望这一篇的总结可以帮助到路过的朋友。

到此这篇关于一文详解Spring事务的实现与本质的文章就介绍到这了,更多相关Spring事务内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 一文详解Spring事务的实现与本质

本文链接: https://www.lsjlt.com/news/203008.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 一文详解Spring事务的实现与本质
    目录一、Spring事务的基础知识1.脏读、不可重复读、幻读2.事务的隔离级别3.事务的传播机制二、Spring事务的实现方式1.编程式事务2.声明式事务三、Spring事务的本质四...
    99+
    2023-05-14
    Spring事务实现 Spring事务本质 Spring事务
  • Spring事务的实现方法与本质是什么
    这篇文章主要介绍了Spring事务的实现方法与本质是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Spring事务的实现方法与本质是什么文章都会有所收获,下面我们一起来看看吧。一、Spring事务的基础知识...
    99+
    2023-07-05
  • Spring的事务详解
    事务简介 事务在逻辑上是一组操作,要么执行,要不都不执行。主要是针对数据库而言的,比如说 MySQL。 为了保证事务是正确可靠的,在数据库进行写入或者更新操作时,就必须得表现出 ACID 的 4 个重要特性: 原子性(Atomicity):...
    99+
    2023-08-20
    spring java
  • Java与Oracle实现事务(JDBC事务)实例详解
    Java与Oracle实现事务(JDBC事务)实例详解J2EE支持JDBC事务、JTA事务和容器事务事务,这里说一下怎样实现JDBC事务。       JDBC事务是由Connec...
    99+
    2023-05-31
    java jdbc事务 ava
  • 一文详解Spring AOP的配置与使用
    目录1.关于AOP2.初步使用AOP环境配置3.使用原生Spring API接口实现AOP4.使用自定义类实现AOP5.使用注解实现AOP1.关于AOP 面向切面编程(俗称AOP)提...
    99+
    2022-11-13
    Spring AOP配置 Spring AOP使用 Spring AOP
  • 一文搞懂spring boot本地事务@Transactional参数
    目录1. 本地事务1.1. 基本概念1.2. 隔离级别1.3. 相关命令1.4. 传播行为1.4.1. 伪代码练习1.4.2. 改造商品新增代码1.4.3. 测试1:同一servic...
    99+
    2024-04-02
  • C++ 函数参数详解:传出机制的本质与注意事项
    c++++函数参数传递方式有两种:传值调用(不影响实参)和传引用调用(影响实参)。传出参数通过传引用或指针实现,函数可以通过修改参数引用或指针指向的变量来传递值给调用方。使用时需要注意:...
    99+
    2024-04-27
    c++ 函数参数
  • 一文解析spring中事务的传播机制
    今天小编给大家分享的是一文解析spring中事务的传播机制,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获的哦。Spring中的事务Spring的事务其实就是数据库的事务操作,符合ACID标...
    99+
    2023-07-06
  • mysql实现事务的提交与回滚的实例详解
    最近要对数据库的数据进行一个定时迁移,为了防止在执行过程sql语句因为某些原因报错而导致数据转移混乱,因此要对我们的脚本加以事务进行控制。 首先我们建一张tran_test表 CREATE TABLE ...
    99+
    2024-04-02
  • 解读Spring事务是如何实现的
    目录Spring事务如何实现Spring事务实现的几种方式编程式事务管理声明式事务管理总结Spring事务如何实现 1.Spring事务底层是基于数据库事务和AOP机制的 2.首先对...
    99+
    2023-03-19
    Spring事务 Spring事务实现 Spring如何实现事务
  • Spring事务的用法示例与实现原理
    本篇内容主要讲解“Spring事务的用法示例与实现原理”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Spring事务的用法示例与实现原理”吧!关于事务,简单来说,就是为了保证数据完整性而存在的一...
    99+
    2023-06-16
  • Spring事务失效场景实例详解
    1、Spring事务最终依赖的数据库的事务,如果用的是mysql的话,执行引擎要是innodb;因为只有innoDB 支持事务。 2、Spring的事务是原理是aop,所以加事务所在...
    99+
    2024-04-02
  • 一文详解golang延时任务的实现
    目录前言你可以收获正文思维导图实现思路步步为营1、数据流2、数据结构3、初始化延时任务对象4、生产者推送任务5、任务推送信号的处理6、生产者删除任务7、任务删除信号的处理8、任务执行...
    99+
    2023-03-20
    golang延时任务 go 延时
  • 一文详解Python中PO模式的设计与实现
    目录什么是PO模式PO 三层模式PO 设计模式的优点将改写的脚本转为PO设计模式构建基础的 BasePage 层构建首页的 Page 层(HomePage)构建登录页的 Page 层...
    99+
    2024-04-02
  • Spring实现文件上传的配置详解
    添加依赖 主要用来解析request请求流,获取文件字段名、上传文件名、content-type、headers等内容组装成FileItem <!--添加fil...
    99+
    2022-11-13
    Spring 文件上传 配置 Spring 文件上传
  • js默认文本框粘贴事件完美实现详解
    目录前言先上代码代码分析前言 本文实际是用js移动控制光标的位置!解决了网上没有可靠教程的现状 默认情况对一个文本框粘贴,应该会有这样的功能: 粘贴文本后,光标不会回到所有文本的最...
    99+
    2023-01-28
    js默认文本框粘贴事件 js文本框粘贴
  • Spring事务的开启原理详解
    目录@EnableTransactionManagement开启事务原理解析总结 在事务配置类上声明@EnableTransactionManagement注解开启事务 在事...
    99+
    2024-04-02
  • Spring基于Aop实现事务管理流程详细讲解
    目录aop在spring事务中的运用基于纯注解实现spring事务管理基于xml文件实现Spring事务管理aop在spring事务中的运用 在Spring中,AOP和事务管理是两个...
    99+
    2023-05-20
    Spring Aop事务管理 Spring实现事务管理
  • Spring事务是怎么实现的
    本文小编为大家详细介绍“Spring事务是怎么实现的”,内容详细,步骤清晰,细节处理妥当,希望这篇“Spring事务是怎么实现的”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。Spring事务如何实现Spring事...
    99+
    2023-07-05
  • 一文详解Spring security框架的使用
    目录简介实例简介 Spring Security是一个基于Spring框架的安全认证和授权框架,它提供了一套全面的安全解决方案,可以在Web应用、移动应用和Web服务等不同场景下使用...
    99+
    2023-03-23
    Spring security框架使用 Spring security框架 Spring security
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作