Mr. Cappuccino的第53杯咖啡——Mybatis源码分析
Mybatis源码分析
- Mybatis源码分析入口
- 1. 读取配置文件
- 总结
- 2. 解析配置文件
- 核心代码(一)
- 核心代码(二)
- 分析parse()方法
- 分析build()方法
- 总结
- 3. 获取SqlSession
- 总结
- 4. 获取mapper代理对象
- 总结
- 5. 使用mapper代理对象执行Sql语句
- 二级缓存
- 一级缓存
- 总结
Mybatis源码分析入口
本文将根据下面这段代码进行源码分析
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<UserEntity> list = mapper.listUser();
System.out.println(list);
sqlSession.close();
1. 读取配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
ClassLoaderWrapper.java
总结
从入口一路点击进去可以发现底层是通过调用java.lang.ClassLoader#getResourceAsStream方法来读取resources目录下的mybatis-config.xml文件,并得到InputStream对象
2. 解析配置文件
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSessionFactoryBuilder.java
核心代码(一)
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
XMLConfigBuilder.java
XPathParser.java
可以发现底层是将InputStream对象转换成Document对象,并将Document对象保存至当前类(XPathParser)的document属性中
继续回到上一层,点击进入this()方法
XMLConfigBuilder.java
可以发现this()方法主要是在进行部分属性的初始化,并将XPathParser对象保存至当前类(XMLConfigBuilder)的parser属性中。
关键点:初始化了父类的configuration属性。
核心代码(二)
return build(parser.parse());
分析parse()方法
XMLConfigBuilder.java
- 根据Document对象获取节点为configuration的配置信息,并转换成XNode对象
XPathParser.java
- 将XNode对象解析成Configuration对象
XMLConfigBuilder.java
XMLConfigBuilder.java
点击进入addMappers(mapperPackage)方法
Configuration.java
MapperRegistry.java
从这里可以发现parser.parse()主要是在解析配置文件(mybatis-config.xml),具体过程是根据Document对象获取节点为configuration的配置信息,并转换成XNode对象再解析各个节点,重点部分是mappers节点的解析。
在解析mappers节点的代码中可以发现如果是使用package或class注册mapper可以直接注册mapper接口对象,如果是使用url或者resource注册mapper则需要先解析mapper.xml映射文件后并通过namespace找到所绑定的接口对象再进行注册。
mapper的注册是通过MapperRegistry对象完成的,而MapperRegistry则是Configuration对象里面的一个属性,也就是说所有的配置解析完成后都存放在Configuration对象中。
parser.parse()最终返回Configuration对象。
分析build()方法
SqlSessionFactoryBuilder.java
DefaultSqlSessionFactory.java
从这里可以发现SqlSessionFactoryBuilder将得到的Configuration对象建造成DefaultSqlSessionFactory对象,也就是SqlSessionFactory对象。
总结
SqlSessionFactoryBuilder先是通过XMLConfigBuilder解析配置文件并将解析得到的配置装载到Configuration对象中,再将Configuration建造成DefaultSqlSessionFactory对象。
这里采用了建造者设计模式
BaseBuilder:所有解析器的父类,包含配置文件实例,为解析文件提供一些通用的方法;
XMLConfigBuilder:主要负责解析mybatis-config.xml文件;
XMLMapperBuilder:主要负责解析mapper.xml文件;
XMLStatementBuilder:主要负责解析映射文件中的SQL节点;
Configuration对象核心属性释义:
- MapperRegistry:mapper接口动态代理工厂类的注册中心;
- ResultMap:用于解析mapper.xml文件中的resultMap节点,使用ResultMapping来封装id、result等子元素;
- MappedStatement:用于存储mapper.xml文件中的select、insert、update和delete节点,同时还包含了这些节点的很多重要属性;
- SqlSource:用于创建BoundSql,mapper.xml文件中的sql语句会被解析成BoundSql对象,经过解析BoundSql包含的语句最终仅仅包含?占位符,可以直接提交给数据库执行;
3. 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
DefaultSqlSessionFactory.java
Configuration.java
从这里可以看到如果没有设置执行器类型,则会默认使用简单执行器类型
ExecutorType.java
上面枚举类中的三种执行器类型均可通过openSession()传参设置
点击进入openSessionFromDataSource()方法
DefaultSqlSessionFactory.java
openSessionFromDataSource()方法有三个入参:ExecutorType execType(执行器类型)、TransactionIsolationLevel level(事务隔离级别)、boolean autoCommit(是否自动提交)
- 获取TransactionFactory
DefaultSqlSessionFactory.java
TransactionFactory有两种:JdbcTransactionFactory,ManagedTransactionFactory
通过mybatis-config.xml文件进行配置
<transactionManager type="JDBC"/>
这里配置的是JdbcTransactionFactory
- 获取Transaction
JdbcTransactionFactory.java
JdbcTransaction.java
- 根据Transaction和执行器类型获取执行器(核心代码)
Configuration.java
CachingExecutor.java
Mybatis默认使用的执行器是SimpleExecutor,SimpleExecutor的父类是BaseExecutor,BaseExecutor下一共有三个子类也就是三种执行器:BatchExecutor、SimpleExecutor、ReuseExecutor,这三种执行器均可通过传值设置。
cacheEnabled默认值为true,说明Mybatis默认会使用CachingExecutor。进入CachingExecutor类可以发现,CachingExecutor是在上面三种执行器(BaseExecutor)的基础上做了一层包装(装饰器设计模式),先调用CachingExecutor再调用BaseExecutor,是对BaseExecutor类的增强。
cacheEnabled可以通过mybatis-config.xml文件进行配置
<settings><!-- 是否开启二级缓存 --><setting name="cacheEnabled" value="false"/>
</settings>
BaseExecutor是一级缓存(默认开启),默认使用SimpleExecutor,CachingExecutor是二级缓存(默认开启,但还需要做一些额外的配置才能生效)
- 生成DefaultSqlSession
将Configuration、Executor、autoCommit等信息包装成DefaultSqlSession对象,并且返回该对象
总结
openSession()是SqlSessionFactory接口中的一个重载方法,可以配置执行器类型、事务隔离级别、是否自动提交等参数,Configuration负责判断当前使用的执行器(Executor),DefaultSqlSessionFactory最后将Configuration、Executor、autoCommit等信息包装成DefaultSqlSession对象并返回。
这里采用了装饰器设计模式
BaseExecutor是一级缓存(默认开启),BaseExecutor是BatchExecutor、SimpleExecutor、ReuseExecutor三种执行器的父类。
- SimpleExecutor:默认的Executor,每个SQL执行的时候都会创建新的Statement;
- ReuseExecutor:相同的SQL会重复使用Statement;
- BatchExecutor:用于批处理的Executor;
CachingExecutor是二级缓存(默认开启,但还需要做一些额外的配置才能生效)
CachingExecutor:可缓存数据的Executor,用装饰器模式包装了其它的执行器(如BaseExecutor下的三种执行器)
4. 获取mapper代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
DefaultSqlSession.java
Configuration.java
MapperRegistry.java
之前已经对mapper接口进行了注册,这里通过mapper接口类型获取对应的动态代理工厂类(MapperProxyFactory),动态代理工厂类使用JDK动态代理技术生成mapper代理对象并返回该对象。
MapperProxyFactory.java
MapperProxy.java
JDK动态代理技术主要用于拦截和修改方法的调用,在使用mapper代理对象调用mapper接口中的方法时MapperProxy中的invoke方法也会被执行。
总结
根据mapper接口类型从MapperRegistry中获取对应的动态代理工厂类(MapperProxyFactory),动态代理工厂类使用JDK动态代理技术生成mapper代理对象并返回该对象。在使用mapper代理对象调用方法时底层会走MapperProxy中的invoke方法。
这里采用了JDK动态代理设计模式
MapperRegistry:mapper接口动态代理工厂类的注册中心;
MapperProxyFactory:用于生成动态代理的实例对象;
MapperProxy:动态代理回调类;
5. 使用mapper代理对象执行Sql语句
List<UserEntity> list = mapper.listUser();
MapperProxy.java
核心代码
mapperMethod.execute(sqlSession, args);
MapperMethod.java
因为执行的SQL为select,返回值类型为List集合,所以会走executeForMany()方法
DefaultSqlSession.java
这个方法是不是很熟悉,没错,这就是在基于XML方式-原生方式开发用到的方法
List<UserEntity> list = sqlSession.selectList("com.mybatis.mapper.UserMapper.listUser", UserEntity.class);
DefaultSqlSession.java
二级缓存
如果开启了二级缓存则会使用CachingExecutor
CachingExecutor.java
- 获取SQL语句
- 创建缓存key
- 执行查询逻辑
SimpleExecutor中没有query方法,默认走父类(BaseExecutor)
一级缓存
BaseExecutor.java
SimpleExecutor.java
- 初始化RoutingStatementHandler对象
Configuration.java
RoutingStatementHandler.java
- 生成Statement对象
SimpleExecutor.java
2.1. 获取Connection
BaseExecutor.java
JdbcTransaction.java
2.2. 根据不同的StatementHandler创建Statement对象
RoutingStatementHandler.java
BaseStatementHandler.java
Mybatis默认采用PreparedStatementHandler处理器
PreparedStatementHandler.java
2.3. 使用ParameterHandler处理占位符参数
RoutingStatementHandler.java
PreparedStatementHandler.java
DefaultParameterHandler.java
- 执行查询逻辑
RoutingStatementHandler.java
PreparedStatementHandler.java
DefaultResultSetHandler.java
总结
在使用代理对象调用方法时,底层会走MapperProxy中的invoke方法,在执行查询语句时,默认会先从二级缓存(CachingExecutor)中读取数据,如果存在则直接返回,不存在则继续查询一级缓存,如果一级缓存(BaseExecutor)中存在则直接返回,不存在则继续查询数据库,在查询数据库时,总体上使用StatementHandler对象和JDBC进行交互,整个查询流程先是使用ParameterHandler对SQL语句的入参进行处理,待SQL语句被执行完后得到结果集,再使用ResultSetHandler对结果集进行处理并返回。
四大核心接口对象
- Executor(执行器):负责整个SQL执行过程的总体控制;
- StatementHandler(语句处理器):负责和JDBC层的具体交互;
- ParameterHandler(参数处理器):负责PreparedStatement入参的具体设置;
- ResultSetHandler(结果集处理器):负责将JDBC查询的结果映射为Java对象;
StatementHandler
- RoutingStatementHandler:根据StatementType路由到不同的StatementHandler对象;
- SimpleStatementHandler:管理Statement对象并向数据库中推送不需要预编译的SQL语句;
- PreparedStatementHandler:管理Statement对象并向数据库中推送需要预编译的SQL语句;
- CallableStatementHandler:管理Statement对象并调用数据库中的存储过程;
相关文章:

Mr. Cappuccino的第53杯咖啡——Mybatis源码分析
Mybatis源码分析 Mybatis源码分析入口1. 读取配置文件总结 2. 解析配置文件核心代码(一)核心代码(二)分析parse()方法分析build()方法 总结 3. 获取SqlSession总结 4. 获取mapper代理对象总结 5. 使用mapper代理对象执行Sql语句二…...

修改文件格式(查看文件拓展名)
很多时候我们直接把txt文件重命名为xxx.c或者别的文件格式,文件类型依然会是txt,文件名并不会变成我们想要的xxx.c,而是xxx.c.txt,也就是下面这个样子 给大家介绍2种方法去解决这个问题 目录 1.另存为新格式 2.显示文件拓展名 1…...

利用鸿鹄可观测性监控Istio Ingress网关
一、需求描述 在上一篇《利用Vector和鸿鹄搭建微服务应用的可观测性平台》中,阐述了微服务的基本概念、优点及如何利用鸿鹄来处理分布式应用的日志。本文将进一步讨论微服务架构面临的问题、服务网格及鸿鹄处理Istio Gateway的独特优势。 1.1 微服务架构面临的挑战 …...

vscode 前端开发插件 2023
自己记录 安装vscode后必装插件 chinesegit 必装没啥可说 随时更新 1.CSS Navigation CTRL点击类名可跳转到对应样式位置。 如果是scss less的话。css peak插件无法生效 2.GitLens — Git supercharged 可以看到每一行的git提交记录。 3.Auto Rename Tag 可以同步更新…...

使用docker部署Wordpress
文章目录 1.创建网络2.创建volume存储3.拉取镜像4.创建mysql容器mysql修改密码 5.创建wordpress容器6.访问localhost:80就可以直接使用啦 1.创建网络 docker network create --subnet172.18.0.0/24 pro-net2.创建volume存储 # mysql 存储 docker volume create volume_mysql…...

7.31黄金最新行情走势分析及多空交易策略
近期有哪些消息面影响黄金走势?黄金多空该如何研判? 黄金消息面解析:上周有重磅数据美联储加息的消息,黄金受其影响波动比较频繁,总体空间40美金。但这个过程跌宕起伏。收线来看黄金在连续上涨三周后迎来一根小阴十…...

Spring框架——AOP注解方式
目录 Spring框架的AOP技术(注解方式) 通知类型 Spring框架的AOP技术(注解方式) 1. 步骤一:创建JavaWEB项目,引入具体的开发的jar包* 先引入Spring框架开发的基本开发包com.springsource.org.apache.commo…...

Java 日志(Logging)如何创建和捕获日志消息和文件
Java允许我们通过日志记录过程来创建和捕获日志消息和文件。 在Java中,日志记录需要框架和API。Java在java.util.logging程序包中具有内置的日志记录框架。 Java 日志组件 下图显示了Java Logging API(java.util.logging)的核心组件和指定…...

em3288 linux_4.19 lvds+tp调试
一、显示配置\rk3288_linux4.19\kernel\arch\arm\boot\dts\rk3288-evb-act8846.dtspanel {compatible "simple-panel";backlight <&backlight>;bus-format <MEDIA_BUS_FMT_RGB666_1X18>;enable-gpios <&gpio1 24 GPIO_ACTIVE_HIGH>;ena…...

Linux 之 systemctl
systemctl 可以控制软件(一般指服务)的启动、关闭、开机自启动 能被systemctl 管理的软件,一般也称 服务 系统内置服务均可被 systemctl 控制第三方软件,如果 自动注册了 可被systemctl 控制第三方软件,如果没有自动…...

【技巧】通过 CMD 走代理下载 Vue
通过 CMD 走代理下载 Vue 在学习或者工作中,有时上网走的是代理模式,就是在浏览器里面配置代理服务的那种。后来在下载 Vue 组件的时候显示请求超时。此时才发先,浏览器代理只能在浏览器里生效,cmd 中不生效,那该怎么办…...

VSCode C/C++多文件编译配置
多文件编译备忘,带注释的地方都需要注意!!! launch.json文件 {// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid830387&quo…...

Autosar通信入门系列05-聊聊一帧Can/CanFD报文发送时间?
本文框架 1. 概述2. 一帧CAN报文发送时间计算3. 一帧CanFD报文的传输时间计算3.1 标准CAN与CANFD两者间的区别3.2 CANFD报文传输时间计算 1. 概述 本篇我们一起看下一帧Can报文发送需要多长时间,下述文章里我们会首先计算下Can分别对应的字节数,再根据传…...

【phaser微信抖音小游戏开发002】hello world!
执行效果: 将以下代码文本内容,放入到game.js中即可。目录结构如下图 import ./js/libs/weapp-adapter import ./js/libs/symbolGameGlobal.window.scrollTo () > { };//防止真机出错 import Phaser from ./js/phaser//引入Phaservar {windowWidth, …...

2023.07.29 驱动开发DAY6
通过epoll实现一个并发服务器 服务器 #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/epoll.h…...

网工必须掌握的5种组网技术,你会了吗?
作者:Insist-- 个人主页:insist--个人主页 作者会持续更新网络知识和python基础知识,期待你的关注 目录 一、VLAN技术 1、VLAN是什么? 2、VLAN的作用 ①提高网络安全性 ②提高了网络的灵活性性 ③增强了网络的健壮性 二、D…...

webpack中文文档
基本安装 首先我们创建一个目录,初始化 npm,然后 在本地安装 webpack,接着安装 webpack-cli(此工具用于在命令行中运行 webpack): mkdir webpack-demo cd webpack-demo npm init -y npm install webpack …...

【Linux指令篇】--- Linux常用指令汇总(克服指令繁杂问题)
文章目录 前言🌟一、Linux基本指令🌟二、ls指令🌏2.1.语法:🌏2.2.功能:🌏2.3.常用选项: 🌟三、pwd指令🌏3.1.语法:🌏3.2.功能…...

硬盘的分类
目前常见的硬盘种类主要有以下2种: 机械硬盘(HDD) 机械硬盘(HDD)是一种利用旋转磁盘和读写头来存储和访问数据的存储设备。它由磁盘、读写头、电机和控制电路等组成,磁盘通常是一种铝合金或玻璃材质的圆盘&…...

el-upload批量手动上传,并用form表单校验上传文件
手动上传设置:auto-upload"false" <el-formref"formData"class"formWidth":model"formData"label-width"120px":rules"rules"><el-form-itemlabel"数据"class"uploadClass"required…...

牛客网Verilog刷题——VL52
牛客网Verilog刷题——VL52 题目答案 题目 请编写一个十进制计数器模块,当mode信号为1,计数器输出信号递增,当mode信号为0,计数器输出信号递减。每次到达0,给出指示信号zero。模块的接口信号图如下: 模块的…...

4-7月预测价差方向准确率统计
月度 预测价差方向准确率 4月 33.6% 5月 28.4% 6月 25.7% 7月 34.2% 4-7月合计 30.6% 准确率计算公式: 其中, D:价差方向预测值(1:实时>日前,0:实时日前,-1:实时<日前&#x…...

《Vue3+Typescript》一个简单的日历组件实现
这是一个没有套路的前端博主,热衷各种前端向的骚操作,经常想到哪就写到哪,如果有感兴趣的技术和前端效果可以留言~博主看到后会去代替大家踩坑的~ 主页: oliver尹的主页 格言: 跌倒了爬起来就好~ 目录 一、…...

第一章 修学旅行
前言 翻了翻文章回收站,好怀念靖和阳的故事啊(航和颜:还有我们别忘啦) 不知道还有没有人记得以前的故事呢…… 那么,我就开始写啦。这是关于密码学的一篇文章,一共2696字:D(累死我…...

如果你也能认识并使用这个低代码平台,那真的是泰酷辣——iVX低代码平台
低代码技术起源是比较悠久的了,尤其是在近些年,随着技术的演进,低代码平台逐渐成为热门趋势。这些平台通过简化应用程序开发流程,减少手动编码,使非专业开发人员也能快速构建复杂应用。为我们的敏捷开发和高效生产贡献…...

uC-OS2 V2.93 STM32L476 移植:系统移植篇
前言 上一篇已经 通过 STM32CubeMX 搭建了 NUCLEO-L476RG STM32L476RG 的 裸机工程,并且下载了 uC-OS2 V2.93 的源码,接下来,开始系统移植 开发环境 win10 64位 Keil uVision5,MDK V5.36 uC-OS2 V2.93 开发板:NUC…...

gitee修改代码提交操作步骤说明
一,简介 本文主要介绍如何从gitee仓库下载文件,本地修改,本地提交,然后再push到远程服务器的操作步骤。供参考,欢迎一起讨论交流~ 二,操作步骤 总的操作步骤分为以下几步 1,远程服务器下载文…...

物联网|可变参数的使用技巧|不一样的点灯实验|访问外设的寄存器|操作寄存器实现点灯|硬件编程的基本流程-学习笔记(11)
文章目录 可变参数的使用技巧第三阶段-初级实验Lesson5:不一样的点灯实验---学习I/O的输出 ☆点灯的电路图分析1 一起看看点灯的电路图Tip1:另一种点灯的电路Tip1:如何访问外设的寄存器2 STM32F407中操作GPIO的方法 通过直接操作寄存器实现点灯实验Tip1:硬件编程的基本流程 2代…...

30. 利用linprog 解决 生产决策问题(matlab程序)
1.简述 线线规划的几个基本性质:【文献[1]第46页】 (1)线性规划问题的可行域如果非空,则是一个凸集-凸多面体; (2)如果线性规划问题有最优解,那么最优解可在可行域的顶点中确定; (3)如果可行域有界,且可行域…...

一百三十九、Kettle——Linux安装Kettle8.2
一、目的 为了方便海豚调度kettle任务,在Linux上安装kettle 二、kettle版本与前提 版本:kettle8.2 pdi-ce-8.2.0.0-342 前提:Linux已经安装好jdk 三、安装步骤 (一)打开安装包所在地 [roothurys22 ~]# cd …...