MyBatis核心流程三大阶段之数据读写阶段

啃下MyBatis源码系列目录

啃下MyBatis源码 - 为什么要看MyBatis源码及源码结构

啃下MyBatis源码 - org.apache.ibatis.logging包源码分析

啃下MyBatis源码 - org.apache.ibatis.datasource包源码分析

啃下MyBatis源码 - org.apache.ibatis.cache包源码分析

啃下MyBatis源码 - MyBatis核心流程三大阶段之初始化阶段

啃下MyBatis源码 - MyBatis核心流程三大阶段之代理阶段(binding模块分析)

啃下MyBatis源码 - MyBatis核心流程三大阶段之数据读写阶段

啃下MyBatis源码 - MyBatis面试题总结

--------------------------------------------------------------------------------------------------------------------------

啃下MyBatis源码 - MyBatis核心流程三大阶段之数据读写阶段

1.MyBatis是怎样的封装jdbc操作的

2.sqlSession查询流程图和Executor内部调用流程图

--------------------------------------------------------------------------------------------------------------------------

1.MyBatis是怎样的封装jdbc操作的

       我们先来回忆一下jdbc代码:

//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");     
//2.获取连接conn
Connection con=DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123");
//3.创建查询接口
Statement sta= con.createStatement();
//4.执行SQL,返回结果集
ResultSet rs= sta.executeQuery("SELECT * FROM `user`");
//5.对结果集数据进行操作
User user = new User();
user.setUserName(String.valueOf(rs.getObject(1)));

       其中第一步加载驱动在MyBatis的初始化阶段就已经完成了,数据读写阶段就是处理sqlSession.executeQuery的阶段,对应JDBC第二步获取连接开始,到返回结果集封装对象结束。那MyBatis究竟是怎样封装JDBC操作的呢?我们先从sqlSession的默认实现DefaultSqlSession开始入手:

       可以看到该类包含一个核心组件Executor(执行器),查询相关操作最终都借助该组件实现,那么我们来看一下Executor的关系类图:

       BaseExecutor:基础抽象类,实现了executor接口的大部分方法,主要提供了缓存管理和事务管理的能力,使用了模板模式,doUpdate,doQuery,doQueryCursor 等方法的具体实现交给不同的子类进行实现

       CachingExecutor:直接实现Executor接口,使用装饰器模式提供二级缓存能力。先从二级缓存查,缓存没有命中再从数据库查,最后将结果添加到缓存中。如果在xml文件中配置了cache节点,则会创建CachingExecutor。

       BatchExecutor:BaseExecutor具体子类实现,在doUpdate方法中,提供批量执行多条SQL语句的能力;

       SimpleExecutor:BaseExecutor具体子类实现且为默认配置,在doQuery方法中使用PrepareStatement对象访问数据库, 每次访问都要创建新的 PrepareStatement对象;

       ReuseExecutor:BaseExecutor具体子类实现,与SimpleExecutor不同的是,在doQuery方法中,使用预编译PrepareStatement对象访问数据库,访问时,会重用缓存中的statement对象,而不是每次都创建新的PrepareStatement。

       一下子丢出来这么多执行器有点蒙,没关系我们跟进一个查询流程走下来就清楚了。首先从DefaultSqlSession开始,我们调用的sqlSession.selectList方法:

       可以看到只有BaseExecutor和CachingExecutor两个类重写了query方法,而CachingExecutor类前面也说过,在Configuration类初始化的时候如果在XML中配置了<cache>节点的话,则会用装饰器模式对基础执行器进行增强,使其拥有二级缓存能力,并且我们也可以看到在初始化Executor时是通过设定的类型来决定初始化哪一个执行器子类。

       好的我们继续跟进BaseExecutor的query()方法:

       可以看到首先通过MappedStatement拿到对应的SQL信息BoundSql,再封装一级缓存值CacheKey,具体的查询为先从一级缓存拿,如果一级缓存为空,就从数据库加载数据,具体从数据库查询的方法源码:

       我们跟进默认实现SimpleExecutor的doQuery方法:

       这段代码有两点值得我们注意,一个是prepareStatement(handler, ms.getStatementLog());这个方法,我们跟进去会发现:

       终于找到了我们熟悉的JDBC代码,获取Connection,创建Statement查询接口;再一个是我们看到了四个新面孔,四种不同的处理器,一起来看下StatementHandler体系结构类图:

       BaseStatementHandler: 所有子类的抽象父类,定义了初始化statement的操作顺序,由具体子类实例化不同的statement

       CallableStatementHandler:调用存储过程

       PreparedStatementHandler:使用预编译PrepareStatement对象访问数据库

       RoutingStatementHandler:Excutor组件真正实例化的子类,使用静态代理模式,根据上下文决定创建哪个具体实体类

       SimpleStatementHandler:直接使用statement对象访问数据库,无须参数化

RoutingStatementHandler类源码,很清晰的静态代理

       接上文调用SimpleStatementHandler的query方法:

     jdbc的execute()方法也找到了,最后借助DefaultResultSetHandler对数据库返回的结果集进行封装,返回用户指定的实体类型。handleResultSets()方法部分源码:

     处理结果集的过程略复杂,这里只简单的梳理下MyBaits对于结果集封装的步骤:

  1. 创建multipleResults集合,保存最终返回的结果。

  2. 取出第一个结果集

  3. 获取对应的resultMap

  4. 根据resultMap转化结果集,转换成目标对象后添加到multipleResults集合;

  5. resultset.close()关闭结果集,将multipleResults集合返回

2.sqlSession查询流程图和Executor内部调用流程图

sqlSession查询流程图:

Executor内部调用流程图:

     至此MyBatis核心流程最后一个阶段:数据读写阶段完成。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值