「一」【Mybatis系列】深入理解Mybatis之Executor执行器

1、JDBC执行过程回顾

JDBC执行过程回顾

1.1原生JDBC操作说明

  • 获取数据库驱动的方式
    第一种是:直接注册数据库驱动
    DriverManager.registerDriver(new Driver());
    第二种是:利用反射机制间接加载数据库驱劝,推荐用第二种
    Class.forName("com.mysql.jdbc.Driver");
  • 取得数据库连接对象Connection
    Connection conn = DriverManager.getConnection(数据库连接URL,用户名,密码);
  • 执行SQL
    insert/update/delete:PreparedStatement .executeUpdate(sql)返回值表示影响记录的行数
    select:PreparedStatement .exeucteQuery();返回值表示符合条件的记录

1.2 着重介绍一下预编译器 Statement 介绍

通过该组件来发送对应的SQL与参数

  • 简单 Statement
  • 预处理 Statement
  • 存储过程 Statement

后者继承自前者,也就是说简单执行器的所有功能,预处理执行器和存储过程执行器都有

1.3 如图所示

在这里插入图片描述

这里把Statement叫做执行器,只是一种说法,有些文章里也会叫做SQL处理器,但实质是一个东西

1.4 Statement 中非常规方法

  1. addBatch(): 批处理操作,将多个SQL合并在一起,最后调用executeBatch 一起发送至数据库执行

    在这里插入图片描述

  2. setFetchSize():设置从数据库每次读取的数量单位。该举措是为了防止一次性从数据库加载数据过多,导致内存溢出。

    在这里插入图片描述

    在这里插入图片描述

2.MyBatis执行过程

在这里插入图片描述

2.1各个组件的作用

  1. 接口代理: 其目的是简化对MyBatis使用,底层使用动态代理实现。
  2. Sql会话: 提供增删改查API,其本身不作任何业务逻辑的处理,所有处理都交给执行器。这是一个典型的门面模式设计。

    在这里插入图片描述

  3. 执行器: 核心作用是处理SQL请求、事物管理、维护缓存以及批处理等。执行器在的角色更像是一个管理员,接收SQL请求,然后根据缓存、批处理等逻辑来决定如何执行这个SQL请求。并交给JDBC处理器执行具体SQL。
  4. JDBC处理器:他的作用就是用于通过JDBC具体处理SQL和参数的。在会话中每调用一次CRUD,JDBC处理器就会生成一个实例与之对应(命中缓存除外)。

请注意在一次SQL会话过程当中四个组件的实例比值分别是 1:1:1:n 。

各个组件关系可以通过下面这张图了解。一个SQL请求通过会话到达执行器,然后交给对应的JDBC处理器进行处理。另外所有的组件都不是线程安全的,不能跨线程使用

在这里插入图片描述

3.Executor 执行器组件

Executor是MyBatis执行者接口,执行器的功能包括:

  1. 基本功能:改、查,没有增删的原因是,所有的增删操作都可以归结到改。
  2. 缓存维护:这里的缓存主要是为一级缓存服务,功能包括创建缓存Key、清理缓存、判断缓存是否存在。
  3. 事物管理:提交、回滚、关闭、批处理刷新。

对于这个接口MyBatis是有三个实现子类。分别是:

  1. SimpleExecutor:简单执行器
  2. ReuseExecutor:重用执行器
  3. BatchExecutor:批处理执行器

    在这里插入图片描述

3.1 简单执行器 SimpleExecutor

SimpleExecutor是默认执行器,它的行为是每处理一次会话当中的SQl请求都会通过对应的StatementHandler 构建一个新个Statement,这就会导致即使是相同SQL语句无法重用Statement,所以就有了(ReuseExecutor)可重用执行器

3.2 可重用执行器 ReuseExecutor

ReuseExecutor 区别在于他会将在会话期间内的Statement进行缓存,并使用SQL语句作为Key。所以当执行下一请求的时候,不在重复构建Statement,而是从缓存中取出并设置参数,然后执行。

这也说明为啥执行器不能跨线程调用,这会导致两个线程给同一个Statement 设置不同场景参数。

在这里插入图片描述

3.3 批处理执行器 BatchExecutor

BatchExecutor 顾名思议,它就是用来作批处理的。但会将所 有SQL请求集中起来,最后调用Executor.flushStatements()方法时一次性将所有请求发送至数据库.

这里它是利用了Statement中的addBath 机制吗?不一定,因为只有连续相同的SQL语句并且相同的SQL映射声明,才会重用Statement,并利用其批处理功能。否则会构建一个新的Satement然后在flushStatements() 时一次执行。这么做的原因是它要保证执行顺序。跟调用顺序一至。

在这里插入图片描述


假设上图中相同的线条颜色,就是相同的SQL语句。为了保证执行顺序只有绿色线条合并成一个Statement而两条黄线不能,否则就会导致,后面的黄线先于中间的绿线执行,有违调用顺序
前面我们所说Executor其中有一个职责是负责缓存维护,以及事物管理。这三执行器并没有涉及,这部分逻辑去哪了呢?别急,缓存和事物无论采用哪种执行器,都会涉及,这属于公共逻辑。所以就完全有必要三个类之上抽象出一个基础执行器用来处理公共逻辑。

3.4 基础执行器 BaseExecutor

BaseExecutor基础执行器主要是用于维护缓存和事物。事物是通过会话中调用commit、rollback进行管理。重点在于缓存这块它是如何处理的? (这里的缓存是指一级缓存),它实现了Executor中的Query与update方法。会话中SQL请求,正是调用的这两个方法。Query方法中处理一级缓存逻辑,即根据SQL及参数判断缓存中是否存在数据,有就走缓存。否则就会调用子类的doQuery() 方法去查询数据库,然后在设置缓存。在doUpdate() 中主要是用于清空缓存。

3.5 缓存执行器 CachingExecutor

Executor 的子类还有一个CachingExecutor,这是用于处理二级缓存的。为什么不把它和一级缓存一起处理呢?因为二级缓存和一级缓存相对独立的逻辑,而且二级缓存可以通过参数控制关闭,而一级缓存是不可以的。综上原因把二级缓存单独抽出来处理。抽取的方式采用了装饰者设计模式,即在CachingExecutor 对原有的执行器进行包装,处理完二级缓存逻辑之后,把SQL执行相关的逻辑交给实至的Executor处理。

在这里插入图片描述

4.执行器总结

执行器的种类有:基础执行器简单执行器重用执行器批处理执行器,此外通过装饰器形式添加了一个缓存执行器。对应功能包括缓存处理事物处理重用处理批处理,这些是多个SQL执行中有共性地方。执行器存在的意义就是去处理这些共性。 如果说每个SQL调用是独立的,不需要缓存,不需要事物也不需集中在一起进行批处理的话,Executor也就没有存在的必要。但事实上这些都是MyBatis中不可或缺的特性。所以才设计出Executor这个组件。

在这里插入图片描述

参考源码阅读网鲁班老师课《MyBatis源码解析大合集》内容详情参见

https://www.bilibili.com/video/BV1Tp4y1X7FM?from=search&seid=9615281135221050046&spm_id_from=333.337.0.0

原文地址:https://blog.csdn.net/weixin_42470732/article/details/121568829

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


1.pom.xml引入依赖 <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" &qu
准备工作 ① 创建数据库&数据表 ## 创建数据库 CREATE DATABASE `dbtest1`; ## 创建数据表 CREATE TABLE `t_user` ( `id` INT NOT NULL AUTO_INCREMENT, `username` VARCHAR(20) DEF
MyBatis逆向工程是指根据数据库表结构自动生成对应的实体类、Mapper接口以及SQL映射文件的过程。这个过程可以通过MyBatis提供的逆向工程工具来完成,极大地方便了开发人员,避免了重复的代码编写,提高了开发效率。 创建逆向工程的步骤 1、添加依赖&插件 <!-- 控制Mave
MyBatis获取参数值的两种方式:${}和#{} ${}的本质就是字符串拼接,#{}的本质就是占位符赋值。 ${}使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;但是#{}使用占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,可以自
resultMap作用是处理数据表中字段与java实体类中属性的映射关系。 准备工作 ① 创建数据库&数据表 CREATE DATABASE `dbtest1`; CREATE TABLE `t_emp` ( `emp_id` int NOT NULL AUTO_INCREMENT, `em
EHCache缓存针对于MyBatis的二级缓存。 MyBatis默认二级缓存是SqlSessionFactory级别的。 添加依赖 <!-- MyBatis-EHCache整合包 --> <dependency> <groupId>org.mybatis.cac
MyBatis 提供了一级缓存和二级缓存的支持,用于提高数据库查询的性能,减少不必要的数据库访问。 一级缓存(SqlSession 级别的缓存) 一级缓存是 MyBatis 中最细粒度的缓存,也称为本地缓存。它存在于每个 SqlSession 的生命周期中,当 SqlSession 被关闭或清空时,
动态SQL是 MyBatis 中非常强大且灵活的功能,允许你根据不同的条件构建SQL查询。 这主要通过 <if>、<choose>、<when>、<otherwise>、<foreach>等标签实现。 查询场景 /** * 根据条件查询员工
本教程操作系统:windows10系统、DELL G3电脑。 MyBatis 是一个优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。在 MyBatis 中,配置数据库连接是非常重要的第一步。下面将详细介绍如何配置 MyBatis 的
今天小编给大家分享的是MyBatis批量查询、插入、更新、删除如何实现,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。
今天小编给大家分享的是Mybatis操作多数据源实现的方法,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获...
本篇文章和大家了解一下mybatis集成到spring的方式有哪些。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。1 前言1.1 集成spring前使用mybat...
今天小编给大家分享的是mybatis-plus分页查询的3种方法,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获...
本篇内容主要讲解“mybatis之BaseTypeHandler怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“mybatis...
这篇文章主要介绍了mybatisforeach怎么传两个参数的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇mybatisforeach怎...
这篇“MyBatis映射文件中parameterType与resultType怎么使用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的...
这篇文章主要介绍“MyBatis怎么获取自动生成的键值”,在日常操作中,相信很多人在MyBatis怎么获取自动生成的键值问题上存在疑惑,小编查阅了各式资料,整理出
这篇文章主要讲解了“怎么去掉IntelliJIDEA中mybatis对应的xml文件警告”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入...
这篇文章主要介绍“MybatisPlus使用@TableId主键id自增长无效如何解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这...