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

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

1、实例代码

在实例搭建文章中,通过 SqlSession 对象查询数据,可乐写了两种方法。

①、常规的需要我们拼接 statement 方式;

②、xxxMapper.interface 接口代理方式;

对应下面两种方法:

  1. //根据id查询person表数据
  2. @Test
  3. public void testSelectPersonById() {
  4. /*这个字符串由 PersonMapper.xml 文件中 两个部分构成
  5. <mapper namespace="com.itcoke.mapper.PersonMapper"> 的 namespace 的值
  6. <select id="selectPersonById" > id 值
  7. */
  8. String namespace = "com.itcoke.mapper.PersonMapper";
  9. String method = "selectPersonById";
  10. //根据 sqlSessionFactory 产生 session
  11. SqlSession sqlSession = sessionFactory.openSession();
  12. Person person = sqlSession.selectOne(namespace + "." + method, 1L);
  13. System.out.println(person);
  14. sqlSession.close();
  15. }
  16. //根据id查询person表数据
  17. //通过接口代理的方式
  18. @Test
  19. public void testInterfaceSelectPersonById() {
  20. //根据 sqlSessionFactory 产生 session
  21. SqlSession sqlSession = sessionFactory.openSession();
  22. PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
  23. Person person = mapper.selectPersonById(1L);
  24. System.out.println(person);
  25. sqlSession.close();
  26. }

本篇文章可乐讲给大家介绍第一种原生方式,其实第二种接口代理最后也是走的第一种方式,这个我们下篇文章具体介绍。

2、构建过程图示

3、代码剖析

3.1 Executor

我们通过 DefaultSessionFactory.openSession() 方法获取 sqlSession

其实是可以通过构造方法指定 Executor 的类型,比如:

  1. SqlSession sqlSession = sessionFactory.openSession(ExecutorType.SIMPLE);

再看生成 Executor 的源代码:

如果不指定执行器类型,直接默认 openSession() 方法,生成的是 CachingExecutor 执行器,这里的 cacheEnabled 其实是默认开启二级缓存的配置,在 mybatis-config.xml 文件中.

并且需要注意的是这里 new CachingExecutor(executor),传进去了一个 SimpleExecutor 对象,后面和数据库交互的实际上是该对象。


得到了 SqlSession,接下来看这段代码:

  1. Person person = sqlSession.selectOne(namespace + "." + method, 1L);

直接看上面源码的第 76 行代码:

  1. 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 行源码:

  1. 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 行代码:

  1. 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的更多相关文章

  1. Mybatis源码解析(四) —— SqlSession是如何实现数据库操作的?

    Mybatis源码解析(四) -- SqlSession是如何实现数据库操作的?   如果拿一次数据库请求操作做比喻,那么前面3篇文章就是在做请求准备,真正执行操作的是本篇文章要讲述的内容.正如标题一 ...

  2. 【MyBatis源码解析】MyBatis一二级缓存

    MyBatis缓存 我们知道,频繁的数据库操作是非常耗费性能的(主要是因为对于DB而言,数据是持久化在磁盘中的,因此查询操作需要通过IO,IO操作速度相比内存操作速度慢了好几个量级),尤其是对于一些相 ...

  3. mybatis源码-解析配置文件(三)之配置文件Configuration解析

    目录 1. 简介 1.1 系列内容 1.2 适合对象 1.3 本文内容 2. 配置文件 2.1 mysql.properties 2.2 mybatis-config.xml 3. Configura ...

  4. Mybatis源码解析,一步一步从浅入深(一):创建准备工程

    Spring SpringMVC Mybatis(简称ssm)是一个很流行的java web框架,而Mybatis作为ORM 持久层框架,因其灵活简单,深受青睐.而且现在的招聘职位中都要求应试者熟悉M ...

  5. Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码

    在文章:Mybatis源码解析,一步一步从浅入深(一):创建准备工程,中我们为了解析mybatis源码创建了一个mybatis的简单工程(源码已上传github,链接在文章末尾),并实现了一个查询功能 ...

  6. Mybatis源码解析,一步一步从浅入深(六):映射代理类的获取

    在文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码中我们提到了两个问题: 1,为什么在以前的代码流程中从来没有addMapper,而这里却有getMapper? 2,UserDao ...

  7. Mybatis源码解析,一步一步从浅入深(七):执行查询

    一,前言 我们在文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码的最后一步说到执行查询的关键代码: result = sqlSession.selectOne(command.ge ...

  8. Mybatis源码解析(一) —— mybatis与Spring是如何整合的?

    Mybatis源码解析(一) -- mybatis与Spring是如何整合的?   从大学开始接触mybatis到现在差不多快3年了吧,最近寻思着使用3年了,我却还不清楚其内部实现细节,比如: 它是如 ...

  9. Mybatis源码解析(三) —— Mapper代理类的生成

    Mybatis源码解析(三) -- Mapper代理类的生成   在本系列第一篇文章已经讲述过在Mybatis-Spring项目中,是通过 MapperFactoryBean 的 getObject( ...

随机推荐

  1. Java集合框架全解

    Collection 集合 集合接口有2个基本方法: public interface Collection<E> { //向集合中添加元素.如果添加元素确实改变了集合就返回 true, ...

  2. Unity3D学习笔记3——Unity Shader的初步使用

    目录 1. 概述 2. 详论 2.1. 创建材质 2.2. 着色器 2.2.1. 名称 2.2.2. 属性 2.2.3. SubShader 2.2.3.1. 标签(Tags) 2.2.3.2. 渲染 ...

  3. shiro反序列化550、721

    shiro550反序列化 获取docker镜像 docker pull medicean/vulapps:s_shiro_1 重启docker systemctl restart docker 启动d ...

  4. MERCY靶机

    仅供个人娱乐 靶机信息 下载地址:https://drive.google.com/uc?id=1YzsW1lCKjo_WEr6Pk511DXQBFyMMR14y&export=downloa ...

  5. Centos8 Tomcat 开机自启配置

    第一步:修改catalina.sh文件 # vim 编辑 Tomcat bin/catalina.sh 文件.增加如下内容 CATALINA_PID="$CATALINA_BASE/bin/ ...

  6. 面试官疯狂问我:char和varchar的区别 怎么办?愣着干嘛?进来白嫖啊!

    MySQL的修仙之路,图文谈谈如何学MySQL.如何进阶!(已发布) 面前突击!33道数据库高频面试题,你值得拥有!(已发布) 大家常说的基数是什么?(已发布) 讲讲什么是慢查!如何监控?如何排查?( ...

  7. 题解CF757B

    题目 题意:在 \(s\) 数组中找出尽可能多的数使得他们的最大公约数 \(>1\) 既然最大公约数 \(>1\),\(s\) 数组的值域是 \(1 \le s_i \le 10^5\), ...

  8. C++水仙花 (如:153 = 1*1*1 + 5*5*5 + 3*3*3)

    1 #include <iostream> 2 #include <ctime> 3 using namespace std; 4 5 int main() 6 { 7 int ...

  9. iptables 及容器网络分析

    本文独立博客阅读地址:https://ryan4yin.space/posts/iptables-and-container-networks/ 本文仅针对 ipv4 网络 iptables 提供了包 ...

  10. .NetCore+OpenSSL实现Https

    前言 最近,有时间研究了一下HTTPS安全通信的原理,感兴趣的同学可以看下上一篇博文深入理解Https如何保证通信安全 ,随即联想到近段时间开发的.NetCore项目,.NetCore API应用程序 ...