Mybatis如何执行Select语句,你真的知道吗?
持续原创输出,点击上方蓝字关注我吧
作者:不才陈某
博客:https://chenjiabing666.github.io
前言
本篇文章是Myabtis源码分析的第三篇,前两篇分别介绍了Mybatis的重要组件和围绕着Mybatis中的重要组件教大家如何阅读源码的一些方法,有了前面两篇文章的基础,来看这篇文章的才不会觉得吃力,如果没有看过的朋友,陈某建议去看看,两篇文章分别是Mybatis源码解析之六剑客和Mybatis源码如何阅读,教你一招!!!。 今天接上一篇,围绕Mybatis中的 selectList()
来看一看Mybatis底层到底做了什么,有什么高级的地方。
环境准备
本篇文章讲的一切内容都是基于 Mybatis3.5
和SpringBoot-2.3.3.RELEASE
。由于此篇文章是基于前两篇文章的基础之上,因此重复的内容不再详细赘述了。
撸起袖子就是干
二话不说,先来一张流程图,Mybatis六剑客,如下:
上图中的这六剑客在前面两篇文章中已经介绍的非常清楚了,此处略过。为什么源码解析的每一篇文章中都要放一张这个流程图呢?因为Mybatis底层就是围绕着这六剑客展开的,我们需要从全局掌握Mybatis的源码究竟如何执行的。
测试环境搭建
举个栗子:根据用户id查询用户信息,Mapper定义如下:
List<UserInfo> selectList(@Param("userIds") List<String> userIds);
对应XML配置如下:
<mapper namespace="cn.cb.demo.dao.UserMapper">
<!--开启二级缓存-->
<cache/>
<select id="selectList" resultType="cn.cb.demo.domain.UserInfo">
select * from user_info where status=1
and user_id in
<foreach collection="userIds" item="item" open="(" separator="," close=")" >
#{item}
</foreach>
</select>
</mapper>
单元测试如下:
@Test
void contextLoads() {
List<UserInfo> userInfos = userMapper.selectList(Arrays.asList("192","198"));
System.out.println(userInfos);
}
DEBUG走起
具体在哪里打上断点,上篇文章已经讲过了,不再赘述了。
由于SpringBoot与Mybatis整合之后,自动注入的是
SqlSessionTemplate
,因此代码执行到org.mybatis.spring.SqlSessionTemplate#selectList(java.lang.String, java.lang.Object)
,如图1
:
从源码可以看到,实际调用的还是
DefaultSqlSession
中的selectList
方法。如下图2
:
「具体的逻辑如下」:
根据Mapper方法的 全类名
从Mybatis的配置中获取到这条SQL的详细信息,比如paramterType
,resultMap
等等。既然开启了二级缓存,肯定先要判断这条SQL是否缓存过,因此实际调用的是 CachingExecutor
这个缓存执行器。
DefaultSqlSession
只是简单的获取SQL的详细配置,最终还是把任务交给了Executor
(当然这里走的是二级缓存,因此交给了缓存执行器)。下面DEBUG走到CachingExecutor#query(MappedStatement, java.lang.Object, RowBounds,ResultHandler)
,源码如下图3
:
上图中的
query
方法实际做了两件事,实际执行的查询还是其中重载的方法List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
,如下图4
:
根据上图源码的分析,其实CachingExecutor执行的逻辑并不是很难,反倒很容易理解,「具体的逻辑如下」:
如果开启了二级缓存,先根据 cacheKey
从二级缓存中查询,如果查询到了直接返回如果未开启二级缓存,再执行 BaseExecutor
中的query方法从一级缓存中查询。如果二级缓存中未查询到数据,再执行 BaseExecutor
中的query方法从一级缓存中查询。将查询到的结果存入到二级缓存中。
BaseExecutor
中的query
方法无非就是从一级缓存中取数据,没查到再从数据库中取数据,一级缓存实际就是一个Map结构,这里不再细说,真正执行SQL从数据库中取数据的是SimpleExecutor
中的public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
方法,源码如下图5
:
从上面的源码也是可以知道,在真正执行SQL之前,是要调用
prepareStatement(handler, ms.getStatementLog())
方法做一些参数的预处理的,其中涉及到了六大剑客的另外两位,分别是ParameterHandler
和TypeHandler
,源码如图6
:
从上图可以知道设置SQL参数的真正方法是
handler.parameterize(stmt)
,真正执行的是DefaultParameterHandler
中的setParameters
方法,由于篇幅较长,简单的说一下思路:获取所有参数的映射 循环遍历,获取参数的值,使用对应的 TypeHandler
将其转换成相应类型的参数。真正的设置参数的方法是 TypeHandler
中setParameter
方法
继续
图6
的逻辑,参数已经设置完了,此时就该执行SQL了,真正执行SQL的是PreparedStatementHandler
中的<E> List<E> query(Statement statement, ResultHandler resultHandler)
方法,源码如下图7
:
上图的逻辑其实很简单,一个是JDBC执行SQL语句,一个是调用六剑客之一的
ResultSetHandler
对结果进行处理。真正对结果进行处理的是
DefaultResultSetHandler
中的handleResultSets
方法,源码比较复杂,这里就不再展示了,具体的逻辑如下:获取结果映射( resultMap
),如果没有指定,使用内置的结果映射遍历结果集,对SQL返回的每个结果通过结果集和 TypeHandler
进行结果映射。返回结果
ResultSetHandler对结果处理结束之后就会返回。至此一条
selectList()
如何执行的大概心里已经有了把握,其他的更新,删除都是大同小异。
总结
Mybatis的源码算是几种常用框架中比较简单的,都是围绕六大组件进行的,只要搞懂了每个组件是什么角色,有什么作用,一切都会很简单。
一条select语句简单执行的逻辑总结如下(前提:「默认配置」):
「SqlSesion」: #SqlSessionTemplate.selectList()
实际调用#DefaultSqlSession.selectList()
「Executor」: #DefaultSqlSession.quer()
实际调用的是#CachingExecutor().query()
,如果二级缓存中存在直接返回,不存在调用#BaseExecutor.quer()
查询一级缓存,如果一级缓存中存在直接返回。不存在调用#SimpleExecutor.doQuery()
方法查询数据库。「StatementHandler」: #SimpleExecutor.doQuery()
生成StatementHandler
实例,执行#PreparedStatementHandler.parameterize()
方法设置参数,实际调用的是#ParamterHandler.setParameters()
方法,该方法内部调用TypeHandler.setParameter()
方法进行类型转换;参数设置成功后,调用#PreparedStatementHandler.parameterize().query()
方法执行SQL,返回结果「ResultSetHandler」: #DefaultResultSetHandler.handleResultSets()
对返回的结果进行处理,内部调用#TypeHandler.getResult()
对结果进行类型转换。全部映射完成,返回结果。
以上就是六剑客在Select的执行流程,如果有错误之处欢迎指正,如果觉得陈某写得不错,有所收获,关注分享一波。
Mybatis如何执行Select语句,你真的知道吗?的更多相关文章
- (3)一起来看下使用mybatis框架的select语句的源码执行流程吧
本文是作者原创,版权归作者所有.若要转载,请注明出处.本文以简单的select语句为例,只贴我觉得比较重要的源码,其他不重要非关键的就不贴了 主流程和insert语句差不多,这里主要讲不同的流程,前面 ...
- SQL 查询总是先执行SELECT语句吗?你们都错了!
SELECT语句中子句的顺序.SELECT语句中使用时必须遵循的次序. 经过一段时间的学习,我们知道了SELECT语句超简版的语法如下: SELECT 字段名 FROM 表名 后来,我们又陆续学习了W ...
- MyBatis(二):Select语句传递参数的集中方案
从别人说的方案中看出,传递参数方案还挺多,不如自己整理下,以便以后使用过程中有个笔记回忆录. 1.传递一个参数的用法: 配置文件 <select id="getById" r ...
- MyBatis直接执行sql语句mapper
<select id="queryBySql" resultType="HashMap"> <![CDATA[ ${sql} ]]> & ...
- 在mybatis执行SQL语句之前进行拦击处理
转载自:http://blog.csdn.net/hfmbook/article/details/41985853 比较适用于在分页时候进行拦截.对分页的SQL语句通过封装处理,处理成不同的分页sql ...
- 原来select语句在MySQL中是这样执行的!看完又涨见识了!这回我要碾压面试官!
大家好,我是冰河~~ MySQL作为互联网行业使用最多的关系型数据库之一,与其免费.开源的特性是密不可分的.然而,很多小伙伴工作了很多年,只知道使用MySQL进行CRUD操作,这也导致很多小伙伴工作多 ...
- 10.1(java学习笔记)JDBC基本操作(连接,执行SQL语句,获取结果集)
一.JDBC JDBC的全称是java database connection java数据库连接. 在java中需要对数据库进行一系列的操作,这时就需要使用JDBC. sun公司制定了关于数据库操作 ...
- 如何阻止SELECT * 语句
我们每个人都知道是个不好的做法,但有时我们还是要这样做:我们执行SELECT * 语句.这个方法有很多弊端: 你从你的表里返回每个列,甚至后期加的列.想下如果你的查询里将来加上了VARCHAR(MAX ...
- 在HibernateTemplate里执行Sql语句
如下所示只能执行非Select语句: public static void executeSQL(HibernateTemplate hibernateTemplate, String sql) { ...
随机推荐
- dota2输入法无候选框?
win10自带的微软拼音在dota2中不会显示候选框,或者说是选词框. 这种情况下只能选择其他输入法. 我选择的是搜狗输入法(此随笔添加时的最新版),在dota2中有选词框. 网上有些人说要改兼容性, ...
- 在 Go 语言中,我为什么使用接口
强调一下是我个人的见解以及接口在 Go 语言中的意义. 如果您写代码已经有了一段时间,我可能不需要过多解释接口所带来的好处,但是在深入探讨 Go 语言中的接口前,我想花一两分钟先来简单介绍一下接口. ...
- python爬虫抖音 个人资料 仅供学习参考 切勿用于商业
本文仅供学习参考 切勿用于商业 本次爬取使用fiddler+模拟器(下载抖音APP)+pycharm 1. 下载最新版本的fiddler(自行百度下载),以及相关配置 1.1.依次点击,菜单栏-Too ...
- python 09 数据包 异常处理
pickle模块操作文件 pickle.dump(obj, file[, protocol]) 序列化对象,并将结果数据流写入到文件对象中.参数protocol是序列化模式,默认值为0,表示以文本的形 ...
- 编译gawk出现问题,没有安装gawk。
今天编译kernal的时候出现了一个错误:GNU awk is required for lib/memtype.h made by memtypes.awk..查了资料,原来是没有安装gawk的缘故 ...
- python chardet模块查看字符编码方式
电脑配置:联想笔记本电脑 windows8系统 Python版本:2.7.8 本文章撰写时间:2014.12.25 作者:陈东陈 阅读说明: 1.本文都是先解释,后放图片: 2.文中斜体部分要么为需要 ...
- “DNAT+云链接+CDN”加速方案,助力出海企业落地生长
摘要:“DNAT+云链接+CDN”加速方案,真正释放技术红利,真诚助力企业出海. 随着国内互联网行业的人口红利逐渐消失,本土互联网市场竞争不断加剧,加之国家多项“走出去”政策的推动,越来越多的中国互联 ...
- MyBatis源码分析之核心处理层
目录 1 传统方式源码剖析 1.1 初始化流程 1.2 执行SQL流程 1.2.1 获取SqlSession 1.2.2 执行SqlSession接口 1.2.3 执行Executor接口 1.2.4 ...
- Java面试题(反射篇+对象拷贝篇)
反射 57.什么是反射? 反射主要是指程序可以访问.检测和修改它本身状态或行为的一种能力 Java反射: 在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否 ...
- 焦大:以后seo排名核心是用户需求点的挖掘
http://www.wocaoseo.com/thread-61-1-1.html 给我一个用户需求点,我便能拗动任何seo排名.-焦大 前不久我看博客上有人留言咨询能否做seo这个词的排名,对于这 ...