MyBatis执行一条sql语句的流程(源码解析)

news2025/1/7 13:51:32

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

MyBatis执行一条sql语句的流程(源码解析)

  • MyBatis执行sql语句的流程
  • 加载配置文件
    • 加载配置文件的流程
  • 创建sqlsessionFactory对象
    • 解析Mapper
    • 创建sqlsessionFactory流程
  • 获取sqlsession
  • 创建mapper代理
  • 执行mapper方法
  • 总结:MyBatis执行一条sql语句的流程


MyBatis执行sql语句的流程

    //<1> 加载配置文件
    InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
    //<2> 创建sessionFactory对象
    SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
    //<3> 获取sqlSession对象信息
    SqlSession session = sessionFactory.openSession();
    //<4> 构建映射器的代理对象
    SysUserMapper mapper = session.getMapper(SysUserMapper.class);
    //<5>调用相关方法信息
    SysUserPO sysUserPO = mapper.selectById(1L);

加载配置文件

我们进入<1>处的方法的:
在这里插入图片描述
我们发现一个陌生的对象classLoaderWrapper,看着像一个类加载器,我们进入这个类中查看:
在这里插入图片描述
发现这个对象包含两个类加载器,那么classLoaderWrapper也是关于进行类加载的对象。
我们进入getResourceAsStream方法中查看:
在这里插入图片描述
注意这里传入了一个空的类加载器对象,进入最底层:
在这里插入图片描述我们发现这里传入了一个类加载器的数组,并且遍历了这个类加载器数组,然后尝试让类加载加载这个资源,加载成功后就立即返回。
但是这个类加载器数组是什么呢?我们返回上一层方法查看:
在这里插入图片描述
进入这个返回类加载器数组的方法:

    ClassLoader[] getClassLoaders(ClassLoader classLoader) {
        return new ClassLoader[]{
        //null,传入的时候为null
         classLoader,
         //classLoaderWrapper对象的类加载器变量
         this.defaultClassLoader, 
         //关于当前线程的类加载器
         Thread.currentThread().getContextClassLoader(), 
         //当前类的类加载器
         this.getClass().getClassLoader(), 
         //classLoaderWrapper对象的另一个类加载器变量
         this.systemClassLoader};
    }

加载配置文件的流程

通过以上的代码追踪,<1>的步骤如下:通过classLoaderWrapper对象的类加载器变量对mybatis的配置文件进行加载,返回了一个输入流。

创建sqlsessionFactory对象

步骤<2>中我们发现创建啦一个SqlSessionFactoryBuilder对象并且通过build方法返回了sqlsessionFactory对象,我们进入方法查看:
在这里插入图片描述
该方法内首先通过步骤<1>获取的输入流创建了一个XmlConfigBuilder对象,然后调用了其parse方法,我们先查看parse方法:
在这里插入图片描述
这个方法首先是对mybatis配置文件标签进行了解析,并且返回了configuration对象,那么这个解析配置的方法应该是对configration对象的属性进行了填充,那么这个configuration对象是什么呢?我们进入这个类查看:
在这里插入图片描述
可以看到Configuration类中含有许多变量,包括我们很熟悉的缓存、请求映射和返回结果映射,我们其实就可以想到整个解析配置的方法中应该是对配置文件中的每个标签进行了解析然后填充到Configuration对象中,我们查看这个解析方法:

解析Mapper

在这里插入图片描述
进入这个方法中,我们可以发现确实如此,对每个标签进行了解析,我们查看一个很关键的方法mapperElement:
在这里插入图片描述

我们发现生成了一个迭代器,应该是对mappers的多个子标签mapper进行了遍历,然后获取mapper标签的多个属性,可以看到mapper存在三个属性,分别是resource、url、class,由下方的非空判断可知这三者是互斥的,进行判断后,由通过属性对每一个mapper进行加载获取输入流,然后又创建了XmlMapperBuilder,调用其parse方法对每一个mapper进行解析,进入方法:
在这里插入图片描述
我们发现,第一个方法对mapper标签进行了解析,我们进入第一个方法:
在这里插入图片描述
可以看到,这个方法对mapper标签下的每一条sql进行了解析,包括缓存、请求映射、响应结果映射、查询类型等,我们注意上方我框起来的方法:获取mapper的命名空间,并且存储在了一个对象中。
我们接着查看第二个方法:
在这里插入图片描述
还记得上面讲的吗,我们获取对mapper进行解析时存储的mapper的命名空间,然后通过命名空间进行加载获取了mapper的类型,然后这个addMapper方法看起来好像是对configuration对象的属性进行了填充,并且传入了mapper的类型,我们点进去查看:
在这里插入图片描述
这里又出现了MapperRegistry对象,是Configuration对象的变量,继续查看:
在这里插入图片描述在这里插入图片描述
这里创建了一个MapperProxyFactory对象,似乎是创建mapper代理工厂,并且把mapper和代理工厂放入一个map集合中。
我们再回到sqlsessionFactory的创建:
在这里插入图片描述
发现我们之前通过XmlConfigBuider解析的配置文件的标签以及通过XmlMapperBuilder解析的每一个mapper的标签得到的Configuration对象,通过这个Configuration对象创建了DefalutSqlsessionFactory。

创建sqlsessionFactory流程

首先创建了XmlConfigBuilder对象,解析mybatis配置文件,来填充Configuration,在解析<mappers标签过程中,创建了XmlMapperBuilder对象解析每一个mapper中的标签,并且利用了Configuration对象的mapperRegistry的map变量,存储了键为mapper类型,值为mapper代理工厂。

获取sqlsession

进入方法最底层:


    private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Transaction tx = null;

        DefaultSqlSession var8;
        try {
        // 获取sqlsessionFactory的configuration变量的环境
            Environment environment = this.configuration.getEnvironment();
        // 通过环境获取事务工厂
            TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
        // 创建新的事务
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
        // 通过configuration创建Executor
            Executor executor = this.configuration.newExecutor(tx, execType);
        // 通过Configuration和Executor创建sqlSession
            var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
        } catch (Exception var12) {
            this.closeTransaction(tx);
            throw ExceptionFactory.wrapException("Error opening session.  Cause: " + var12, var12);
        } finally {
            ErrorContext.instance().reset();
        }

        return var8;
    }

创建mapper代理

第<4>步返回了一个mapper对象,但不是实际的mapper,而是mapper的代理对象,我们进入方法最底层:
在这里插入图片描述
我们发现会从关于mapper代理工厂的map集合中,通过mapper类型获取代理工厂,并且通过代理工厂创建代理对象,点进去查看:
在这里插入图片描述
mapper代理对象的创建是基于JDK动态代理实现的,通过Proxy的newProxyInstance方法创建:
在这里插入图片描述
而创建代理的方法第三个参数是InvocationHandler,那么mapperProxy一定实现了InvocationHandler这个类,并且当我们调用代理对象的方法时,代理类的方法会中转到InvocationHandler对象的invoke方法,然后就可以在这个方法中对原方法做出一些增强,具体可参考:代理模式:静态代理和动态代理(JDK动态代理原理)

执行mapper方法

我们来查看使用代理模式做了哪些增强:
在这里插入图片描述
在这个方法中,首先判断这个类是不是接口,由于JDK动态代理生成的代理类需要继承Proxy类,又需要实现或继承被代理类来获取方法信息,但是java是多实现单继承,因此这个类必须是接口,然后判断是不是默认方法。
查看第一个方法:
在这里插入图片描述
发现是从缓存中获取一个MapperMethod对象,如果不存在进行创建,创建时可以发现闯入了mapper接口、调用的方法以及sqlsession的configuration对象,并且执行方法时也调用了其execute方法,我们看一下MapperMethod到底是什么:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

其存在两个对象,分别是sql命令和方法签名,sql命令包括sql的类型和statement的id,方法签名包括方法的返回类型以及一些信息。
查看execute方法
在这里插入图片描述
首先会根据sql的类型,来选择执行方法,然后将参数装换为sql可以识别的参数,然后再次交给sqlsession来执行方法,我们随机进入一个执行方法查看:

在这里插入图片描述
可以发现会通过Configuration创建MappedStatement,然后由Executor来执行相关方法

总结:MyBatis执行一条sql语句的流程

加载配置文件:通过类加载器ClassLoaderWrapper以及一些其他的类加载器加载mybatis配置文件获得输入流。
SqlsessionFactory的创建:通过XmlConfigBuilder通过输入流解析配置文件的标签,来填充Configuration属性,在解析的mappers标签的过程中,遍历每一个mapper标签,通过mapper标签的属性解析相应的mapper,并通过XmlMapperBuilder对相应的mapper类的标签进行解析,在此期间,通过mapper的命名空间获取mapper类,并且创建mapper代理工厂,以mapper类为键,mapper代理工厂为值放入mapperRegistry的map集合中。
获取sqlsession:通过SqlsessionFactory的Configuration对象获取环境变量,通过环境变量获取事务工厂并且创建事务,然后通过事务和环境创建Executor对象,最后通过创建的Executor对象和事务来创建DefaultSqlsession并返回
获取代理对象:根据mapper类从关于mapper代理工厂的键值对中取出mapper代理工厂并且创建代理对象返回
执行相关方法:由于创建代理对象时传入了MapperProxy对象,其实现了InvocationHandler接口,因此调用代理相关方式时会进入MapperProxy的invoke方法,在该方法内首先会从缓存中获取MapperMethod对象,然后调用其Execute方法,根据sql的类型然后由Executor执行。

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

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

相关文章

Git命令行的使用

目录 一、什么是Git 1、本地仓库 vs 远端仓库 本地仓库 远端仓库 2、.git vs .gitignore .git .gitignore 二、使用Git命令 1、安装git 2、git首次使用需要配置用户邮箱和用户名 3、上传目录/文件到远端仓库步骤 1&#xff09;创建放置文件的目录 2&#xff09;cd…

法律专业legal case的留学论文写作技巧分析(1)

对于法律专业的留学生而言&#xff0c;案例的分析是写作的重要方面。无论留学的国家是英、美、澳洲还是加拿大&#xff0c;它们都属于case law 的法律体系。一个非常显著的特点便是通过对案例进行分析和提炼&#xff0c;从中总结提炼出principle和rules。case analysis的留学论…

一文理解区块链

一文搞懂区块链 区块链的诞生&#xff0c;源于对 电子货币&#xff08;e-money&#xff09; 的探索需求&#xff0c;即Bitcoin的产生。因此&#xff0c;了解的小伙伴应该知道区块链的常见定义是&#xff1a;不可篡改的分布式账本。 为什么发明“账本”&#xff0c;而不是直接发…

C 实现植物大战僵尸(四)

C 实现植物大战僵尸&#xff08;四&#xff09; 音频稍卡顿问题&#xff0c;用了 SFML 三方库已优化解决 安装 SFML 资源下载 https://www.sfml-dev.org/download/sfml/2.6.2/ C 实现植物大战僵尸&#xff0c;完结撒花&#xff08;还有个音频稍卡顿的性能问题&#xff0c;待…

编程入门(2)-2024年 RAD Studio version 12发布综述

随着2024年即将画上句号&#xff0c;我想借此机会回顾一下我们在这一年中发布的一些Embarcadero产品、行业趋势&#xff0c;并感谢我们尊贵的客户们对我们的产品一如既往的支持。这一年对我们来说充满了激动人心的变化和发展&#xff0c;我们非常高兴能与您一起踏上这段旅程。 …

[Day 12]904.水果成篮

今天给带来的题目是滑动窗口的另一种题目&#xff0c;之前我们讲了滑动窗口题目中长度最小的子数组&#xff0c;今天这个题目实际上是求长度最长的子数组 题目描述&#xff1a;力扣链接 904.水果成篮 你正在探访一家农场&#xff0c;农场从左到右种植了一排果树。这些树用一个整…

SpringBoot 2.6 集成es 7.17

引言 在现代应用开发中&#xff0c;Elasticsearch作为一个强大的搜索引擎和分析引擎&#xff0c;已经成为许多项目不可或缺的一部分。Spring Boot作为Java生态中最受欢迎的微服务框架之一&#xff0c;其对Elasticsearch的支持自然也是开发者关注的焦点。本文将详细介绍如何在S…

【数据仓库】hive on Tez配置

hive on Tez 搭建 前提是hive4.0hadoop3.2.2数仓已搭建完成&#xff0c;现在只是更换其执行引擎 为Tez。搭建可参考【数据仓库】hive hadoop数仓搭建实践文章。 Tez 下载 下载地址 https://archive.apache.org/dist/tez/ 官网地址 https://tez.apache.org/releases/apac…

云备份项目--客户端编写

文章目录 10. 客户端工具类10.1 整体的类10.2 测试 11 客户端数据管理类11.1 整体的类11.2 测试 12. 客户端业务处理12.1 整体的类 完整的代码–gitee链接 10. 客户端工具类 10.1 整体的类 在windows平台下进行开发&#xff0c;Util.hpp实际上是客户端FileUtil.hpp和JsonUtil…

MySQL 的事务与多版本并发控制(MVCC)的那些事

什么是事务原子性:一致性隔离性 问题1: 为什么MySQL要使用mvcc实现隔离性而不使用 锁 解决并发问题?持久性 问题2: MySQL 不是磁盘数据库吗,持久化为什么是 redo log 保证的?问题 3: redo log 储存了什么东西,持久化(崩溃恢复是怎么做的?)问题 4 : MySQL 的 bing log (二进制…

Eplan 项目结构(高层代号、安装地点、位置代号)

Eplan中的项目结构分为3个层次&#xff1a; &#xff08;1&#xff09;功能面结构。指明这个系统的功能&#xff0c;有什么用途。在EPlan中&#xff0c;指的就是"高层代号&#xff08;&#xff09;"。 一般指的是线体。 &#xff08;2&#xff09;位置面结构。指明该…

OWASP ZAP之API 请求基础知识

ZAP API 提供对 ZAP 大部分核心功能的访问,例如主动扫描器和蜘蛛。ZAP API 在守护进程模式和桌面模式下默认启用。如果您使用 ZAP 桌面,则可以通过访问以下屏幕来配置 API: Tools -> Options -> API。 ZAP 需要 API 密钥才能通过 REST API 执行特定操作。必须在所有 …

短信通知在 IOS 17/18 中不起作用?这是修复方法

问题 “我最近将 iPhone 更新到了 iOS 17/18。我真的很兴奋&#xff0c;直到我发现 iOS 17/18 中没有 iMessage 文本通知。此后我的兴奋变成了失望。请告诉我如何解决这个问题&#xff1f; ” 我们知道这可能是一个大问题&#xff0c;因为我们通常不会打开消息应用程序&#…

从0开始的opencv之旅(1)cv::Mat的使用

目录 Mat 存储方法 创建一个指定像素方式的图像。 尽管我们完全可以把cv::Mat当作一个黑盒&#xff0c;但是笔者的建议是仍然要深入理解和学习cv::Mat自身的构造逻辑和存储原理&#xff0c;这样在查找问题&#xff0c;或者是遇到一些奇奇怪怪的图像显示问题的时候能够快速的想…

机场安全项目|基于改进 YOLOv8 的机场飞鸟实时目标检测方法

目录 论文信息 背景 摘要 YOLOv8模型结构 模型改进 FFC3 模块 CSPPF 模块 数据集增强策略 实验结果 消融实验 对比实验 结论 论文信息 《科学技术与工程》2024年第24卷第32期刊载了中国民用航空飞行学院空中交通管理学院孔建国, 张向伟, 赵志伟, 梁海军的论文——…

《Rust权威指南》学习笔记(二)

枚举enum 1.枚举的定义和使用如下图所示&#xff1a; 定义时还可以给枚举的成员指定数据类型&#xff0c;例如&#xff1a;enum IpAddr{V4(u8, u8, u8, u8),V6(String),}。枚举的变体都位于标识符的命名空间下&#xff0c;使用::进行分隔。 2.一个特殊的枚举Option&#xff0…

OSI模型的网络层中产生拥塞的主要原因?

&#xff08; 1 &#xff09;缓冲区容量有限&#xff1b;&#xff08; 1.5 分&#xff09; &#xff08; 2 &#xff09;传输线路的带宽有限&#xff1b;&#xff08; 1.5 分&#xff09; &#xff08; 3 &#xff09;网络结点的处理能力有限&#xff1b;&#xff08; 1 分…

linux上安装MySQL教程

1.准备好MySQL压缩包&#xff0c;并进行解压 tar -xvf mysql-5.7.28-1.el7.x86_64.rpm-bundle.tar -C /usr/local 2.检查是否有mariadb数据库 rpm -aq|grep mariadb 关于mariadb:是MySQL的一个分支&#xff0c;主要由开源社区在维护&#xff0c;采用GPL授权许可 MariaDB的目…

R语言中的时间序列分析·

1 数据集说明 AirPassengers 1949~1960年每月乘坐飞机的乘客数 JohnsonJohnson Johnson&Johnson每股季度收入 nhtemp 康涅狄格州纽黑文地区从1912年至1971年每年的平均气温 Nile 尼罗河的流量 sunspots 1749年~1983年月平均太阳黑子数 2 相关包 xts、forecast、tser…

LookingGlass使用

背景 Looking Glass 是一款开源应用程序&#xff0c;可以直接使用显卡直通的windows虚拟机。 常见环境是Linux hostwindows guest&#xff0c;基本部署结构图&#xff1a; 编译 git clone --recursive https://github.com/gnif/LookingGlass.git编译client mkdir client/b…