Mybatis源码解析4——SqlSession
上一篇文章中,我们介绍了 SqlSessionFactory 的创建过程,忘记了的,可以回顾一下,或者看下下面这张图也行。

接下来,可乐讲给大家介绍 Mybatis 中另一个重量级嘉宾——SqlSession,有了这个对象,我们就能对数据进行一顿操作了。大家伙小板凳搬起来,请看可乐为大家一一道来。

1、实例代码
在实例搭建文章中,通过 SqlSession 对象查询数据,可乐写了两种方法。
①、常规的需要我们拼接 statement 方式;
②、xxxMapper.interface 接口代理方式;

对应下面两种方法:
//根据id查询person表数据
@Test
public void testSelectPersonById() {
/*这个字符串由 PersonMapper.xml 文件中 两个部分构成
<mapper namespace="com.itcoke.mapper.PersonMapper"> 的 namespace 的值
<select id="selectPersonById" > id 值
*/
String namespace = "com.itcoke.mapper.PersonMapper";
String method = "selectPersonById";
//根据 sqlSessionFactory 产生 session
SqlSession sqlSession = sessionFactory.openSession();
Person person = sqlSession.selectOne(namespace + "." + method, 1L);
System.out.println(person);
sqlSession.close();
}
//根据id查询person表数据
//通过接口代理的方式
@Test
public void testInterfaceSelectPersonById() {
//根据 sqlSessionFactory 产生 session
SqlSession sqlSession = sessionFactory.openSession();
PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
Person person = mapper.selectPersonById(1L);
System.out.println(person);
sqlSession.close();
}
本篇文章可乐讲给大家介绍第一种原生方式,其实第二种接口代理最后也是走的第一种方式,这个我们下篇文章具体介绍。
2、构建过程图示

3、代码剖析
3.1 Executor
我们通过 DefaultSessionFactory.openSession() 方法获取 sqlSession

其实是可以通过构造方法指定 Executor 的类型,比如:
SqlSession sqlSession = sessionFactory.openSession(ExecutorType.SIMPLE);
再看生成 Executor 的源代码:

如果不指定执行器类型,直接默认 openSession() 方法,生成的是 CachingExecutor 执行器,这里的 cacheEnabled 其实是默认开启二级缓存的配置,在 mybatis-config.xml 文件中.
并且需要注意的是这里 new CachingExecutor(executor),传进去了一个 SimpleExecutor 对象,后面和数据库交互的实际上是该对象。


得到了 SqlSession,接下来看这段代码:
Person person = sqlSession.selectOne(namespace + "." + method, 1L);

直接看上面源码的第 76 行代码:
List<T> list = this.selectList(statement, parameter);

在上一篇文章介绍 SqlSessionFactory 的构建过程时,我们说了 configuration 对象的组成:

看上面的源码得到 MappedStatement 对象,包含了我们在 mapper.xml 文件中配置的 sql 语句。

执行 executor.query() 方法,注意,这里的 executor 是 CachingExecutor:

这段源码,我们可以得到两个信息:
①、获取我们指定配置的boundSql 对象,包含我们配置的 sql 语句和参数信息。
②、根据相关信息得到一个缓存 key,通过这个key,连续两次相同的查询,第二次可以不去查数据库,直接获取缓存的数据。
接着我们继续看 query() 方法:

看源码,也就是说先去查缓存,缓存命中了直接返回数据,没有命中就执行:delegate.query() 方法。
这里的 delegate 是上文我们说的构造 Executor 传进来得 SimpleExecutor 对象。

关于 mybatis 缓存后面可乐会专门写一篇文章来仔细介绍,这里我们先梳理主线,看上面第 156 行代码,缓存查不到,从数据库里面查。
继续跟 queryFromDatabase() 方法:

3.2 StatementHandler
执行到上面第 61 行源码:
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
跟进去:

这里构造的是一个 RoutingStatementHandler 对象,聪明的你一听听名字都知道会路由生成别的对象。
没错,是根据传入的 statementType 生成具体的对象:

在 MappedStatement 对象中,默认 statementType 是 PERPARED:

也就是这里最终生成的 StatementHandler 实际上是 PreparedStatementHandler 对象。
通常情况下:
①、不带参数的 SQL语句执行,会生成 SimpleStatementHandler 对象。
②、带参数的 SQL 语句执行,会生成 PreparedStatementHandler 对象。
③、存储过程执行,会生成 CallableStatementHandler 对象。
3.3 ParameterHandler
再回到 SimpleExecutor 的 doQuery() 方法:

看第 62 行代码:
stmt = prepareStatement(handler, ms.getStatementLog());
跟进去:

这里第 86 行获取数据库连接。
第 88 行,进行参数处理,说直接点,就是将 SQL 语句中的 “?” 替换成我们传入的具体值。
但是我们知道 Java对象参数和数据库参数是不一样的,那么肯定还会做参数类型转换,没错,就是通过下面将要介绍 TypeHandler 来完成。
3.4 TypeHandler
也就是将 Java 类型和 数据库类型进行互相转换。

Mybatis 提供给了很多内置的参数转换,基本上不需要我们自己去定义。

当然,聪明的你可能会问了,假如这些都不满足呢?假如我要自定义一些类型呢?
不用担心,Mybatis 给我们预留了自定义类型的接口,如果你想自定义类型,通常分为两步:
①、实现 org.apache.ibatis.type.TypeHandler 接口, 或继承类 org.apache.ibatis.type.BaseTypeHandler
②、在配置文件中配置自定义的 TypeHnadler。
这里可乐就不做详细描述了,官网写的也很清楚:
https://mybatis.org/mybatis-3/zh/configuration.html#typeHandlers
3.4 ResultSetHandler
还是回到 SimpleExecutor 的 doQuery() 方法:

上一步我们得到了 PrepraedStatementHandler 对象,接着看 handler.query() 方法:

通过执行 ps.execute() 方法,得到结果集,然后通过 resultSetHandler 去处理结果集。
4、总结
这样,可乐就给大家完整的讲解了如何通过 SqlSession 进行一次数据库查询操作,但是正如文章开头所言,可乐给大家介绍了两种查询方式,一种是需要自己拼接 namespace+method 语句,另一种是通过 接口的形式。其实这两种方式是一样的,namespace 就是接口的包名(对应xxxMapper.xml 的namespace名称),method 就是接口的方法名(对应到xxxMapper.xml 的每个SQL语句的 id 属性),通过两者拼接,我们能去 xxxMapper.xml 文件中定位到具体的 SQL 语句。
很明显,通过接口的形式避免了我们写字符串错误的可能,实际开发中,我们基本上都是这种方式,下一篇文章,可乐将给大家揭秘这种方式的奥秘。
Mybatis源码解析4——SqlSession的更多相关文章
- Mybatis源码解析(四) —— SqlSession是如何实现数据库操作的?
Mybatis源码解析(四) -- SqlSession是如何实现数据库操作的? 如果拿一次数据库请求操作做比喻,那么前面3篇文章就是在做请求准备,真正执行操作的是本篇文章要讲述的内容.正如标题一 ...
- 【MyBatis源码解析】MyBatis一二级缓存
MyBatis缓存 我们知道,频繁的数据库操作是非常耗费性能的(主要是因为对于DB而言,数据是持久化在磁盘中的,因此查询操作需要通过IO,IO操作速度相比内存操作速度慢了好几个量级),尤其是对于一些相 ...
- mybatis源码-解析配置文件(三)之配置文件Configuration解析
目录 1. 简介 1.1 系列内容 1.2 适合对象 1.3 本文内容 2. 配置文件 2.1 mysql.properties 2.2 mybatis-config.xml 3. Configura ...
- Mybatis源码解析,一步一步从浅入深(一):创建准备工程
Spring SpringMVC Mybatis(简称ssm)是一个很流行的java web框架,而Mybatis作为ORM 持久层框架,因其灵活简单,深受青睐.而且现在的招聘职位中都要求应试者熟悉M ...
- Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码
在文章:Mybatis源码解析,一步一步从浅入深(一):创建准备工程,中我们为了解析mybatis源码创建了一个mybatis的简单工程(源码已上传github,链接在文章末尾),并实现了一个查询功能 ...
- Mybatis源码解析,一步一步从浅入深(六):映射代理类的获取
在文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码中我们提到了两个问题: 1,为什么在以前的代码流程中从来没有addMapper,而这里却有getMapper? 2,UserDao ...
- Mybatis源码解析,一步一步从浅入深(七):执行查询
一,前言 我们在文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码的最后一步说到执行查询的关键代码: result = sqlSession.selectOne(command.ge ...
- Mybatis源码解析(一) —— mybatis与Spring是如何整合的?
Mybatis源码解析(一) -- mybatis与Spring是如何整合的? 从大学开始接触mybatis到现在差不多快3年了吧,最近寻思着使用3年了,我却还不清楚其内部实现细节,比如: 它是如 ...
- Mybatis源码解析(三) —— Mapper代理类的生成
Mybatis源码解析(三) -- Mapper代理类的生成 在本系列第一篇文章已经讲述过在Mybatis-Spring项目中,是通过 MapperFactoryBean 的 getObject( ...
随机推荐
- tomcat与springmvc 结合 之---第19篇 springmvc 加载.xml文件的bean 过程
writedby 张艳涛,看springmvc 的源码太难了,怎么办, 这篇文章主要分析了看透springmvc的第9章结尾的 如何解析xml 命名空间标签 <?xml version=&quo ...
- Python实用案例,Python脚本,Python实现自动监测Github项目并打开网页
往期回顾 Python实现文件自动归类 前言: 今天我们就利用Python脚本实现Github项目的更新,提醒方式是邮箱.直接开整~ 项目地址: https://github.com/kenwoodj ...
- leetcode 有效三角形的个数
题目描述: 平明伞兵解法: 既然要求满足三角形要求的三边,简单来说,就是最短两边之和大于第三边,所以,第一步Arrays.sort().先排序,然后直接伞兵暴力法,三重循环.当然最后肯定是能跑出来的, ...
- UI自动化学习笔记- 日志相关操作
一.日志相关 1.日志 概念:日志就是用于记录系统运行时的信息,对一个事件的记录,也称log 1.1 日志的作用 调试程序 了解系统程序运行的情况,是否正常 系统程序运行故障分析与问题定位 用来做用户 ...
- 用好WinSCP,无惧Linux命令
很多人惧怕Linux系统的命令操作模式.实际上对于普通用户来说用到命令的概率非常小. 我们在实践过程中发现管理Linux系统,最多使用如下两个工具: WinSCP(必用):可视化界面工具,实现文件管理 ...
- 自学linux——15.云主机的购买流程及域名的购买备案解析
项目上线流程 一.服务器选配购买 项目上线的服务器必须是外网服务器 1.服务器购买情况 真实服务器(成本过高,购买内部自用) 云服务器(上线首选):阿里云,腾讯云,华为云 2.购买阿里云服务器:htt ...
- RSA算法之学习
一.RSA算法 RSA是非对称加密算法中的代表,它的重要性不言而喻,为了弄清楚RSA算法,我们一起来完成一项任务: 背景:现在是疫情时代,假如小明和女朋友被迫在两个城市,小明为了表达感情,想发给对方一 ...
- 1.9 货仓选址问题——Python
题目描述 在一条数轴上有 N 家商店,它们的坐标分别为 A1~AN. 现在需要在数轴上建立一家货仓,每天清晨,从货仓到每家商店都要运送一车商品. 为了提高效率,求把货仓建在何处,可以使得货仓到每家商店 ...
- 在VMware中安装Centos6值得注意的几点
关于在VMware上安装centos6.9时遇到的几个值得说的点 0x01关于分区 分区时候可以选择默认分区,也可以选择自定义布局,这里选择自定义布局 点击sda,选择创建,再选标准分区->创建 ...
- STM32—DMA存储器到外设
DMA目录 DMA简介 DMA框图 DMA传输数据分析 1.传输的方向 2.传输的数量 3.传输的模式 代码部分 DMA初始化结构体 USART配置函数 DMA配置函数 主函数 DMA简介 DMA(D ...