(八)Mybatis持久化框架原理之不同Executor对比和Spring事务关系

文章目录

  • 1. SqlSession的差异
  • 2. Executor的差异
    • 2.1 SimpleExecutor流程说明
    • 2.2 ReuseExecutor流程说明
    • 2.3 BatchExecutor流程说明
  • 3. Mybatis事务
  • 4. Spring事务
  • 5. 总结

本篇文章主要是由一次批量插入数据而引起的思考与探究,在这篇文章中将会分析不同的Executor和SqlSession的实现原理差异,同时也会分析Mybatis和Spring的事务处理差异并比较他们之间的优先级与关系。

1. SqlSession的差异

Mybatis依赖于SqlSession来完成sql的调用,Mybatis和Spring集成时,SqlSession常用的类型有两种:

  1. DefaultSqlSession:如果通过SqlSessionFactory的openSession方法获取SqlSession,其生成的类型就是DefaultSqlSession。使用该类时需要开发者执行完业务逻辑后自行commit、rollback或close;
  2. SqlSessionTemplate:如果使用的是@Mapper或@MapperScan等方式通过Spring自动扫描注册的方式注入Mapper类,Mapper类则会被SqlSessionTemplate代理。在代理切面中调完方法后会自动commit、rollback或close,无需开发者关心介入。但在切面中实际使用的SqlSession类型依然是DefaultSqlSession。

总结: DefaultSqlSession是Mybatis操作Mapper方法的唯一入口,而SqlSessionTemplate则是使用代理方式包装了一层,在代理方法中使用DefaultSqlSession完成了commit、rollback和close。

所以不难理解为什么SqlSessionTemplate的commit、rollback和close三个方法未实现,调用则报错,因为其只提供代理的模板方法,不提供真实逻辑操作。

DefaultSqlSession类有个autoCommit属性,很多人会误以为这个属性是真正控制事务自动提交的,实际上不是,这个属性只会控制Mybatis的事务管理器是否调用commit、rollback方法,和事务的自动提交没有关系。 SqlSession基本每次事务调用都会生成一个新的。

2. Executor的差异

Mapper的增删改调用的都是Executor的doUpdate方法,查则调用的doQuery方法。

Mybati的Executor可供选择的有三种:

  1. SIMPLE:默认的执行器,实现类SimpleExecutor,其实现非常简单,从Datssource中获取Connection,再用Connection获取Statement实现类,最后执行增删改查;
  2. REUSE:实现类ReuseExecutor,在SIMPLE的基础上加入了Statement对象的缓存,如果对应的sql有Statement对象缓存则直接使用,避免了Statement对象的频繁创建销毁;
  3. BATCH:实现类BatchExecutor,增删改时会把Statement对象缓存起来,并添加到批处理中,在进行查询或commit时将会批量执并清空Statement缓存。

Executor的生命周期和SqlSession基本等同,其中的Transaction对象则是实例化Executor时由SqlSession设置进来的。

2.1 SimpleExecutor流程说明

SimpleExecutor执行sql流程

  • 调用时会从Connection中初始化Statement对象,而Connection会由Transaction对象维护;
  • 获取Statement之后直接调用执行方法,执行sql;
  • 最后关闭Statement对象。

2.2 ReuseExecutor流程说明

ReuseExecutor执行sql流程

  • 用sql判断Statement是否已生成, 如果已生成则使用缓存的Statement对象,并重新设置超时时间;未生成则流程和SimpleExecutor一致;
  • 获取Statement之后直接调用执行方法,执行sql;
  • 调用commit/rollback后会调用doFlushStatements方法清空Statement缓存,相当于只在一次事务中Statement会反复使用,这个步骤没在图中标注。

2.3 BatchExecutor流程说明

BatchExecutor增删改sql流程

  • 判断生成sql和MappedStatement对象和上次调用是否相同,如果相同则只会重新设置Statement对象的超时时间,并更新缓存;否则会重新实例化Statement
  • 调用时会从Connection中初始化Statement对象,而Connection会由Transaction对象维护;
  • 获取Statement后记录当前sql和MappedStatement对象,随后添加到缓存statementList中,并实例化BatchResult添加到缓存batchResultList;
  • 调用Statement的addBatch方法添加到批处理中;

注: BatchExecutor的增删改流程相当于只是在本地做了初始化操作并添加到了缓存中,没有实际调用数据库,因此如果是Mysql数据库,此时是拿不到自增主键的,因为还没有和数据库交互。

BatchExecutor的查询/commit流程图:

BatchExecutor查询/commit流程

  • 从statementList和batchResultList分别获取Statement和BatchResult对象;
  • 执行Statement对象的executeBatch方法执行批量操作;
  • 执行KeyGenerator生成主键并回填;
  • 保存批量操作结果;
  • 最后关闭Statement对象并清空缓存。

查询、commit或rollback时都会调用Executor的doFlushStatements方法,如果是rollback调用,则会直接返回空。只有查询和commit才会执行图片中的流程。

3. Mybatis事务

Mybatis的事务对象Transaction会在SqlSession中实例化Executor时由TransactionFactory实例化,并注入到Executor中。在Executor中实际操作的事务就是Transaction对象,因此Mybatis的事务实际提交与否和Transaction的实现类有关。

TransactionFactory和Transaction对象的对应关系表:

Transaction类型TransactionFactory类型是否默认设置autoCommitcommit/rollback备注说明
JdbcTransactionJdbcTransactionFactory可设置可操作非默认类型,需要开发者手动指定,可通过方法直接操作Connection对象
ManagedTransactionManagedTransactionFactory官方默认不可设置不可操作Mybatis未指定TransactionFactory时的默认类型,负责打开Connection连接,但不进行实际的commit/rollback操作
SpringManagedTransactionSpringManagedTransactionFactorySpring默认不可设置未在Spring事务可操作对接Spring时指定的默认类型,和JdbcTransaction类似,但是不能设置Connection对象的autoCommit属性,同时会判断Connection是否处于Spring的事务管理中,如果是则不会进行commit/rollback操作

由上面的表格内容可反推:Mybatis操作Datasource的Connection是由Transaction来完成的,常用的有两种:

  1. 由ManagedTransactionFactory生成的ManagedTransaction来完成,不能使用ManagedTransaction来控制connection的commit/rollback,只能直接使用Connection;
  2. 由SpringManagedTransactionFactory生成的SpringManagedTransaction来完成,会获取Datasource的自动提交属性,如果autocommit属性为true,则commit/rollback无效,如果autocommit为false,则commit/rollback生效。在Spring的事务管理中commit/rollback也无效。

注意: Druid的defaultAutoCommit属性默认是true,因此Druid会自动提交。

4. Spring事务

Spring事务通常有两种实现方式:

  1. 使用TransactionTemplate显式编程处理;
  2. 使用@Transactional切面进行处理。

使用TransactionTemplate的好处是不会受到任何约束,只要注入了TransactionTemplate,就可以直接使用,而不像@Transactional一样必须要求触发切面逻辑。其实现原理就是帮我们把try-catch块的提交回滚逻辑固定了,开发者只需要关注事务内部的业务逻辑即可。

使用这两种方式都会通过PlatformTransactionManager获取Connection,此时会把autocommit设置为false,因此事务不会自动提交。在切面即将结束时才会调用Connection的commit方法提交事务。

Spring的具体事务操作类是交给PlatformTransactionManager的实现类,如果使用的是Datasource,实现类一般是DataSourceTransactionManager,其实际管理的是由Datasource生成的Connection类,commit/rollback都是使用Connection对应的方法,autoCommit也是Connection的属性。

5. 总结

  1. 事务提交回滚与Datasource生成的Connection对象是否调用commit/rollback或autoCommit属性有关,第三方框架管理事务通过Connection对象操作;
  2. Spring的事务管理优先级大于Mybatis的事务管理,实际事务commit/rollback与否以Spring为主;
  3. Mybatis对接Spring使用的是SpringManagedTransaction,内部使用ThreadLocal完成Spring是否管理事务判断;
  4. 只通过Mybatis操作数据库事务,commit与否的优先级数据源autoCommit>Mybatis;
  5. Spring容器的事务通常由DataSourceTransactionManager管理实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/25171.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue3+springboot+sa-token

sa-token是什么? sa-token官网Sa-Token 是一个轻量级 Java 权限认证框架,主要解决:登录认证、权限认证、单点登录、OAuth2.0、分布式Session会话、微服务网关鉴权 等一系列权限相关问题。 springboot前后端分离集成sa-token maven <!-- Sa-Token 权限认证,在线文档:…

快来速领限量免费亚马逊云科技助理级架构师(SAA)和云从业者50%半价考试券

前几天在上海5/29的亚马逊云科技Summit峰会里&#xff0c;小李哥在现场分享了AWS 13张认证大满贯的心得&#xff08;图1&#xff09;&#xff0c;并且现场招募了自己的云师兄必过班(图2)。 本次必过班也为成员发放AWS SAA(助理级架构师)和云从业者(Cloud Practitioner)50%考试券…

面向对象程序设计

class是关键字&#xff0c;表示要定义类了 类的属性&#xff0c;即定义在类中的变量&#xff08;成员变量&#xff09; 类的行为&#xff0c;即定义在类中的函数&#xff08;成员方法&#xff09; self关键字是成员方法定义的时候&#xff0c;必须填写的。 它用来表示类对象…

AIGC作答《2024年高考作文|新课标I卷》能拿多少分?

AIGC作答《2024年高考作文&#xff5c;新课标I卷》能拿多少分&#xff1f; 一、前言二、题目三、作答 一、前言 如火如荼的2024年高考圆满落幕&#xff0c;在如此Happy的时刻&#xff0c;AIGC技术正以其前所未有的热度席卷全球。它不仅改变了我们获取信息的方式&#xff0c;也…

Rust-10-数据类型

Rust 标准库中包含一系列被称为 集合&#xff08;collections&#xff09;的非常有用的数据结构。大部分其他数据类型都代表一个特定的值&#xff0c;不过集合可以包含多个值。不同于内建的数组和元组类型&#xff0c;这些集合指向的数据是储存在堆上的&#xff0c;这意味着数据…

【risc-v】arm和riscv有什么关系或者联系?

ARM和RISC-V都是基于精简指令集计算&#xff08;RISC&#xff09;原理的处理器架构&#xff0c;它们在设计理念上有一定的联系&#xff0c;但同时存在一些关键的区别&#xff1a; 设计理念&#xff1a;ARM和RISC-V都采用了RISC的核心设计原则&#xff0c;即通过简化指令集来提高…

C++知识点总结(36):深度优先搜索算法

DFS 一、概念二、典型题目1. 题目2. 分析3. 参考答案 三、变形题目1. 路径数量1.1 审题1.2 思路 2. 走迷宫的过程2.1 审题2.2 参考答案 一、概念 深度优先搜索&#xff08;简称 DFS&#xff09;&#xff0c;其工作原理为不撞南墙不回头&#xff0c;能深则深&#xff0c;不能则退…

Element-UI入门

目录 1.什么是Element-UI 2.作用 3.版本历史 4.优缺点 4.1.优点 4.2.缺点 5.应用场景 6.代码示例 7.未来展望 8.总结 1.什么是Element-UI Element-UI 是由饿了么前端团队开发的一套基于 Vue.js 的桌面端组件库。提供了一整套 UI 组件&#xff0c;使开发者能够快速构…

一步一学!如何通过SOLIDWORKS曲面放样绘制花瓶?

SOLIDWORKS中&#xff0c;我们对放样凸台的操作已经非常熟悉。现在&#xff0c;我们将进一步探索曲面菜单栏中的放样成型功能。 1、绘制草图 首先&#xff0c;同普通放样凸台建模相同&#xff0c;绘制放样轮廓及引导线段。 可通过创建基准面布置轮廓&#xff0c;利用穿透选项将…

AVL许可安全性问题

在数字化时代&#xff0c;软件已经成为我们生活和工作中不可或缺的一部分。然而&#xff0c;随着软件应用的广泛普及&#xff0c;安全性问题也日益凸显。如何保障软件使用安全&#xff0c;防止潜在风险&#xff0c;成为了我们必须关注的重要议题。AVL许可作为软件管理的重要组成…

144、二叉树的前序递归遍历

题解&#xff1a; 递归书写三要素&#xff1a; 1&#xff09;确定递归函数的参数和返回值。要确定每次递归所要用到的参数以及需要返回的值 2&#xff09;确定终止条件。操作系统也是用栈的方式实现递归&#xff0c;那么如果不写终止条件或者终止条件写的不对&#xff0c;都…

Android 各个版本名称和特性总结(持续更新)

我们就从Android 5.0开始吧&#xff0c;因为从写文时起&#xff0c;大部分手机都到5.0了。 目录 Android5.0 &#xff08;Lollipop 棒棒糖&#xff09;新特性 Android6.0新特性 Android7.0新特性 Android8.0(O)新特性 Android9.0新特性 Android10.0(Q)新特性 Android11…

定位器追踪器怎么连接手机

定位器追踪器连接手机的方法主要取决于追踪器的类型和功能。下面将列举一些常见的方式来说明如何将定位器追踪器与手机连接&#xff1a; 蓝牙连接 检查设备兼容性&#xff1a;确保你的定位器追踪器支持蓝牙功能&#xff0c;同时手机的蓝牙也已开启。进行配对&#xff1a;在手机…

前端调用接口有参数正常显示返回值,但是打印是undefined

前端调用接口有参数正常显示返回值&#xff0c;但是打印是undefined 这种有几种情况&#xff0c;但总的来说是因为我们做了接口拦截器的处理 一、后端返回code值有误 比如新来的后端忘记传code了。&#xff08;按照公司规范&#xff0c;一般都是200成功码&#xff09; 或者网上…

java程序100道21-30

21.定义一个接口A&#xff0c;有一个String的常量值为Java的 s&#xff0c;有void 的print()方法和String 的getInfo()方法&#xff0c;类X是A的实现类&#xff0c;类A的print()方法输出常量s,方法getInfo()返回“Hello!!!” package Exercises.One_Hundred.Demo21; ​ public…

IO-源码阅读 glibc 2.35

文章目录 参考缓存机制IO_FILE_PLUSfopenfopen_internal_IO_no_init_IO_old_init _IO_new_file_init_internal_IO_link_in _IO_new_file_fopen_IO_file_open fread_IO_fread_IO_sgetn_IO_doallocbuf_IO_file_doallocate_IO_file_stat_IO_setb __underflow_IO_new_file_underflo…

[Cloud Networking] Layer 2

文章目录 1. 什么是Mac Address?2. 如何查找MAC地址&#xff1f;3. 二层数据交换4. [Layer 2 Protocol](https://blog.csdn.net/settingsun1225/article/details/139552315) 1. 什么是Mac Address? MAC 地址是计算机的唯一48位硬件编码&#xff0c;嵌入到网卡中。 MAC地址也…

英特尔:AI落地,未来已来

引言 随着AI技术的发展和大模型的普及&#xff0c;人工智能正在逐渐渗透到我们的日常生活中。2023年5月底&#xff0c;我参加了台北的英特尔技术展&#xff0c;深入了解了英特尔在AI个人电脑领域的最新进展。本文将详细介绍英特尔的新一代移动处理器Lunar Lake&#xff0c;以及…

Spring Data Jpa 实现批量插入或更新

1. BatchConsumer package com.demo.common.hibernate.batch;import com.demo.common.hibernate.querydsl.QueryParameterBuilder;/*** 批量数据消费者接口&#xff0c;用于设置 SQL 参数并执行操作。** param <T> 记录类型的泛型* author xm.z*/ FunctionalInterface p…

02 Linux 调试手段

1、printk 与打印等级 在 Linux 内核中,内核开发者喜欢 printk 来调试,它与 C 库的 printf() 函数类似。 printk() 与 printf() 区别:printk() 提供输出等级。内核会根据这个等级来判断是否在终端或者串口中输出 log。 1)printk 等级 #define KERN_EMERG KERN_SOH &quo…