我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Spring事务的实现方法与本质是什么

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Spring事务的实现方法与本质是什么

这篇文章主要介绍了Spring事务的实现方法与本质是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇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指明他的隔离级别和传播机制,注意这里并没有配置数据源相关操作,数据源仍需要单独在配置文件中进行声明数据源的类型和驱动类以及其他的数据库访问的账号路径超时时间最大连接等信息。

    @Componentpublic 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则必须我们手动进行提交或者回滚,下面是他的伪代码

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

    @Componentpublic 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了,又没有抛出异常我们有没有其他方式进行回滚呢(使用声明式事务时)?其实还有一种方式进行回滚,如下所示:

    @Transactionalpublic 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事务的实现方法与本质是什么”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网行业资讯频道。

    免责声明:

    ① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

    ② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

    Spring事务的实现方法与本质是什么

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

    下载Word文档

    猜你喜欢

    Spring事务的实现方法与本质是什么

    这篇文章主要介绍了Spring事务的实现方法与本质是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Spring事务的实现方法与本质是什么文章都会有所收获,下面我们一起来看看吧。一、Spring事务的基础知识
    2023-07-05

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

    这篇文章主要介绍了Spring中事务的两种实现方式:声明式事务、编程式事务以及他们的本质。文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-05-14

    spring事务提交与回滚的方法是什么

    Spring中事务的提交和回滚是通过编程式事务管理或声明式事务管理来实现的。编程式事务管理:在代码中通过编程的方式进行事务的提交和回滚,通常使用TransactionTemplate类来实现。示例代码如下:@Autowiredpriva
    spring事务提交与回滚的方法是什么
    2024-03-07

    MySQL事务实现的方法是什么

    在MySQL中,可以使用以下方法来实现事务:使用START TRANSACTION、COMMIT和ROLLBACK语句来开始、提交和回滚事务。START TRANSACTION; -- 开始事务-- 执行一系列的操作COMMIT; -
    MySQL事务实现的方法是什么
    2024-03-12

    C++ RBTree红黑树的性质与实现方法是什么

    这篇文章主要讲解了“C++ RBTree红黑树的性质与实现方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++ RBTree红黑树的性质与实现方法是什么”吧!一、红黑树的概念红黑树
    2023-07-05

    Spring事务是怎么实现的

    本文小编为大家详细介绍“Spring事务是怎么实现的”,内容详细,步骤清晰,细节处理妥当,希望这篇“Spring事务是怎么实现的”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。Spring事务如何实现1.Sprin
    2023-07-05

    Spring整合MyBatis的实现方法是什么

    这篇文章主要讲解了“Spring整合MyBatis的实现方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Spring整合MyBatis的实现方法是什么”吧!一、Spring 项目整体
    2023-07-05

    Spring事务的用法示例与实现原理

    本篇内容主要讲解“Spring事务的用法示例与实现原理”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Spring事务的用法示例与实现原理”吧!关于事务,简单来说,就是为了保证数据完整性而存在的一
    2023-06-16

    使用Spring的ApplicationEvent实现本地事件驱动的实现方法

    本文介绍了如何使用Spring的ApplicationEvent实现本地事件驱动,通过自定义事件和监听器,实现模块之间的松耦合,提升代码的可维护性和扩展性。同时还介绍了异步事件和事件传递的相关知识
    2023-05-17

    Quartz与Spring集成的方法是什么

    要将Quartz与Spring集成,可以按照以下步骤进行操作:1. 添加Quartz和Spring的依赖:在项目的pom.xml文件中添加Quartz和Spring的依赖。2. 创建Quartz配置文件:在Spring的配置文件中,可以创建
    2023-10-20

    Node中的异步实现与事件驱动方法是什么

    这篇“Node中的异步实现与事件驱动方法是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Node中的异步实现与事件驱动方
    2023-07-04

    spring与redis集成的方法是什么

    Spring与Redis集成的方法有以下几种:使用Spring Data Redis库:Spring Data Redis是Spring提供的一个用于与Redis数据库进行交互的库。它提供了一系列的注解和工具类,简化了与Redis的交互操作
    2023-10-25

    Spring的事件发布与监听方式是什么

    本篇内容介绍了“Spring的事件发布与监听方式是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!事件主要代码在org.springfra
    2023-07-05

    Spring事务处理Transactional和并发线程的方法是什么

    本篇内容介绍了“Spring事务处理Transactional和并发线程的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Sprin
    2023-06-22

    Spring中编程式事务与声明式事务的区别是什么

    本篇文章为大家展示了Spring中编程式事务与声明式事务的区别是什么,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Spring事务属性我们都知道事务有开始,保存点,提交,回滚,隔离级别等属性。那么S
    2023-05-31

    Activiti7与Spring及Spring Boot整合开发的方法是什么

    这篇文章主要介绍“Activiti7与Spring及Spring Boot整合开发的方法是什么”,在日常操作中,相信很多人在Activiti7与Spring及Spring Boot整合开发的方法是什么问题上存在疑惑,小编查阅了各式资料,整理
    2023-07-05

    Spring七大事务传递机制的实现原理是什么

    这篇“Spring七大事务传递机制的实现原理是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Spring七大事务传递机制
    2023-07-05

    编程热搜

    • Python 学习之路 - Python
      一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
      Python 学习之路 - Python
    • chatgpt的中文全称是什么
      chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
      chatgpt的中文全称是什么
    • C/C++中extern函数使用详解
    • C/C++可变参数的使用
      可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
      C/C++可变参数的使用
    • css样式文件该放在哪里
    • php中数组下标必须是连续的吗
    • Python 3 教程
      Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
      Python 3 教程
    • Python pip包管理
      一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
      Python pip包管理
    • ubuntu如何重新编译内核
    • 改善Java代码之慎用java动态编译

    目录