Mr. Cappuccino的第53杯咖啡——Mybatis源码分析

news2024/11/25 22:46:31

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

在这里插入图片描述

  1. 根据Document对象获取节点为configuration的配置信息,并转换成XNode对象

XPathParser.java

在这里插入图片描述

  1. 将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对象核心属性释义:

  1. MapperRegistry:mapper接口动态代理工厂类的注册中心;
  2. ResultMap:用于解析mapper.xml文件中的resultMap节点,使用ResultMapping来封装id、result等子元素;
  3. MappedStatement:用于存储mapper.xml文件中的select、insert、update和delete节点,同时还包含了这些节点的很多重要属性;
  4. 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(是否自动提交)

  1. 获取TransactionFactory

DefaultSqlSessionFactory.java

在这里插入图片描述

TransactionFactory有两种:JdbcTransactionFactory,ManagedTransactionFactory
通过mybatis-config.xml文件进行配置

在这里插入图片描述

<transactionManager type="JDBC"/>

这里配置的是JdbcTransactionFactory

  1. 获取Transaction

JdbcTransactionFactory.java

在这里插入图片描述

JdbcTransaction.java

在这里插入图片描述

  1. 根据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是二级缓存(默认开启,但还需要做一些额外的配置才能生效)

  1. 生成DefaultSqlSession

在这里插入图片描述

将Configuration、Executor、autoCommit等信息包装成DefaultSqlSession对象,并且返回该对象


总结

openSession()是SqlSessionFactory接口中的一个重载方法,可以配置执行器类型、事务隔离级别、是否自动提交等参数,Configuration负责判断当前使用的执行器(Executor),DefaultSqlSessionFactory最后将Configuration、Executor、autoCommit等信息包装成DefaultSqlSession对象并返回。

这里采用了装饰器设计模式

BaseExecutor是一级缓存(默认开启),BaseExecutor是BatchExecutor、SimpleExecutor、ReuseExecutor三种执行器的父类。

  1. SimpleExecutor:默认的Executor,每个SQL执行的时候都会创建新的Statement;
  2. ReuseExecutor:相同的SQL会重复使用Statement;
  3. 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

在这里插入图片描述

  1. 获取SQL语句

在这里插入图片描述

  1. 创建缓存key

在这里插入图片描述

  1. 执行查询逻辑

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

SimpleExecutor中没有query方法,默认走父类(BaseExecutor)


一级缓存

BaseExecutor.java

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

SimpleExecutor.java

在这里插入图片描述

  1. 初始化RoutingStatementHandler对象

Configuration.java

在这里插入图片描述

RoutingStatementHandler.java

在这里插入图片描述

  1. 生成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

在这里插入图片描述

  1. 执行查询逻辑

RoutingStatementHandler.java

在这里插入图片描述

PreparedStatementHandler.java

在这里插入图片描述

DefaultResultSetHandler.java

在这里插入图片描述


总结

在使用代理对象调用方法时,底层会走MapperProxy中的invoke方法,在执行查询语句时,默认会先从二级缓存(CachingExecutor)中读取数据,如果存在则直接返回,不存在则继续查询一级缓存,如果一级缓存(BaseExecutor)中存在则直接返回,不存在则继续查询数据库,在查询数据库时,总体上使用StatementHandler对象和JDBC进行交互,整个查询流程先是使用ParameterHandler对SQL语句的入参进行处理,待SQL语句被执行完后得到结果集,再使用ResultSetHandler对结果集进行处理并返回。

四大核心接口对象

  1. Executor(执行器):负责整个SQL执行过程的总体控制;
  2. StatementHandler(语句处理器):负责和JDBC层的具体交互;
  3. ParameterHandler(参数处理器):负责PreparedStatement入参的具体设置;
  4. ResultSetHandler(结果集处理器):负责将JDBC查询的结果映射为Java对象;

StatementHandler

  1. RoutingStatementHandler:根据StatementType路由到不同的StatementHandler对象;
  2. SimpleStatementHandler:管理Statement对象并向数据库中推送不需要预编译的SQL语句;
  3. PreparedStatementHandler:管理Statement对象并向数据库中推送需要预编译的SQL语句;
  4. CallableStatementHandler:管理Statement对象并调用数据库中的存储过程;

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

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

相关文章

基于SpringBoot+Vue的会员制医疗预约服务管理信息系统设计与实现(源码+LW+部署文档等)

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

Android Studio log的快捷键和使用

输入logi&#xff0c;然后按下Tab键&#xff0c;会自动补全一条info级别的打印日志。输入logw&#xff0c;按下Tab键&#xff0c;会自动补全一条warn级别的打印日志&#xff0c;以此类推。 如下图所示&#xff1a;

C#项目发布

C#项目发布 vs code 打包iis 配置 vs code 打包 iis 配置

VMware Linux Centos 配置网络并设置为静态ip

在root用户下进行以下操作 1. 查看子网ip和网关 &#xff08;1&#xff09;进入虚拟网络编辑器 &#xff08;2&#xff09;进入NAT设置 &#xff08;3&#xff09;记录子网IP和子网掩码 2. 修改网络配置文件 &#xff08;1&#xff09;cd到网络配置文件路径下 [rootlo…

【视觉SLAM入门】5.1. 特征提取和匹配--FAST,ORB(关键点描述子),2D-2D对极几何,本质矩阵,单应矩阵,三角测量,三角化矛盾

"不言而善应" 0. 基础知识1. 特征提取和匹配1.1 FAST关键点1.2 ORB的关键点--改进FAST1.3 ORB的描述子--BRIEF1.4 总结 2. 对极几何&#xff0c;对极约束2.1 本质矩阵(对极约束)2.1.1 求解本质矩阵2.1.2 恢复相机运动 R &#xff0c; t R&#xff0c;t R&#xff0c;…

推荐几款小众且无广告的软件,你值得拥有

你是否喜欢一些小众且无广告的软件&#xff1f;如果是的话&#xff0c;我这边有一些给你推荐的。 护眼软件——EyeLoveU ​ EyeLoveU是一款免费的护眼软件&#xff0c;可以在你使用电脑一段时间后&#xff0c;提醒你该让眼睛休息。EyeLoveU是一种智能的眼睛保护程序&#xff…

python tkinker界面

import tkinter from PIL import Image, ImageTkdog tkinter.Tk() # 设置图片描绘的坐标&#xff0c;注意乘号是字母x dog.geometry(500x500200100) # 不允许修改大小 dog.resizable(False, False) # 不显示标题栏 dog.overrideredirect(True) # 设置白色透明色&#xff0c;这…

【玩转pandas系列】数据清洗(文末送书福利)

文章目录 一、重复值检测二、元素替换1️⃣ 元素替换replace2️⃣ 数据映射map 三、修改索引1️⃣ 修改索引名rename2️⃣ 设置索引和重置索引 四、数据处理1️⃣ apply与applymap2️⃣ transform 五、异常值处理六、抽样聚合函数1️⃣ 抽样2️⃣ 数学函数 七、分组聚合&#x…

DAY16_VUE基本用法详细版

目录 0 HBuilderX修改注释0 HBuilderX 修改.VUE中的注释颜色1 Vue入门1.1 什么是Vue1.2 Vue优点1.3 Vue案例1.3.1入门案例1.3.2 v-cloak属性1.3.3.1 v-text 指令1.3.3.2 v-html 指令1.3.3.3 v-pre 指令1.3.3.4 v-once 指令1.3.3.5 v-model 指令 1.3.4 MVVM思想 1.4 事件绑定1.4…

OpenLayers入门,OpenLayers如何加载WFS服务的要素资源数据

专栏目录: OpenLayers入门教程汇总目录 前言 本章讲解如何使用OpenLayers加载WFS服务的要素资源数据。 WFS规范介绍 WFS是基于地理要素级别的数据共享和数据操作,WFS规范定义了若干基于地理要素(Feature)级别的数据操作接口,并以 HTTP 作为分布式计算平台。通过 WFS服…

如何将工作可视化管理,工作流程管理

看板利用了对视觉内容的偏好&#xff0c;可以帮助团队理解和分析在工作中发生了什么&#xff0c;遇到了哪些问题和瓶颈&#xff0c;我们可以通过看板更好的可视化工作流程&#xff0c;可以在看板内自定义工作流程&#xff0c; 首先创建工作流任务看板 通过Leangoo领歌敏捷看板…

AD21 PCB设计的高级应用(七)盲埋孔的设置

&#xff08;七&#xff09;盲埋孔的设置 1.盲埋孔的设置2.Pad/Via模板的使用 1.盲埋孔的设置 随着目前便携式产品的设计朝着小型化和高密度的方向发展,PCB的设计难度也越来越大,对 PCB 的生产工艺提出了更高的要求。在目前大部分的便携式产品中 0.65mm间距以下 BGA封装均使用…

C#+WPF上位机开发(模块化+反应式)

在上位机开发领域中&#xff0c;C#与C两种语言是应用最多的两种开发语言&#xff0c;在C语言中&#xff0c;与之搭配的前端框架通常以QT最为常用&#xff0c;而C#语言中&#xff0c;与之搭配的前端框架是Winform和WPF两种框架。今天我们主要讨论一下C#和WPF这一对组合在上位机开…

Android Layout大点兵

原文链接 Android Layout大点兵 智能手机催生了移动互联时代&#xff0c;现如今移动应用越来越成为最为核心的终端。而GUI页面是移动互联终端的标配&#xff0c;做好一个GUI页面&#xff0c;是非常重要的&#xff0c;能极大的提升用户体验和用户满意度。安桌生态&#xff0c;自…

无涯教程-jQuery - width( val )方法函数

width(val)方法设置每个匹配元素的CSS宽度。 width( val ) - 语法 selector.width( val ) 这是此方法使用的所有参数的描述- val - 这是元素的宽度。如果未指定任何显式单位(如em或&#xff05;)&#xff0c;则将" px"连接到该值。 width( val ) - 示例 以…

免费MES系统:助力企业数字化转型的利器

在这个飞速发展的数字化时代&#xff0c;企业的竞争力和生产效率已经与传统模式发生天翻地覆的变化。为了跟上这个变化的步伐并引领未来的生产力&#xff0c;下面就详细介绍免费MES系统的优势和价值。 什么是MES系统&#xff1f; MES系统是一种通过数字化技术实现生产计划、监…

Cocos Store 免费游戏资源下载指南!

Cocos Creator 3.8.0 新版引擎即将发布&#xff0c;如果你还没有使用过 Cocos Creator 引擎&#xff0c;本文就带你从引擎的下载、安装、到游戏源码运行&#xff0c;只需要3分钟搞定&#xff0c;Lets Go! 01 下载 Cocos Dashboard 打开浏览器&#xff0c;进入 Cocos Store 资源…

STM32基础回顾

文章目录 单片机编程的原理GPIO中断EXTI外部中断定时器中断、串口中断 定时器定时器中断配置过程通用定时器输出比较功能&#xff1a;PWM波的生成定时器的输入捕获功能主从触发模式PWMI模式 定时器的编码器接口 DMA简介通信接口USART软件配置流程&#xff1a;1、仅发数据的配置…

2023-07-29:华清远见嵌入式2017年线下班:文件IO笔记

这里写目录标题 华清远见嵌入式2017年线下班&#xff1a;文件IO笔记文件权限文件IO文件创建和打开操作文件关闭操作出错处理创建设备文件 || create || 老师自己忘了文件读操作练习&#xff1a;计算文件的大小&#xff1f;文件写操作练习&#xff1a;打开file1和file2&#xff…

手机设置全局代理ip步骤

在互联网时代&#xff0c;隐私和安全问题备受关注。使用全局代理能够帮助我们保护个人信息&#xff0c;突破地理限制&#xff0c;并提高网络速度。但是&#xff0c;你是否对全局代理的安全性存有疑虑&#xff1f;而且&#xff0c;如何在手机上设置全局代理呢&#xff1f;今天就…