Mybatis流程分析(七): 探寻Mybatis中执行sql语句的"入口"

本系列文章皆在从细节 着手,由浅入深的分析Mybatis框架内部的处理逻辑,带你从一个全新的角度来认识Mybatis的工作原理。

思考,输出,沉淀。用通俗的语言陈述技术,让自己和他人都有所收获。

作者:毅航😜


前言

在前几章:

  1. Mybatis流程分析(五): sql语句与接口中方法绑定的"细节"
  2. Mybatis流程分析(四):Mybatis构建Mapper背后的故事
  3. Mybatis流程分析(六): Mybatis中方法和sql语句的桥梁------MapperProxy

中我们利用大量的篇幅详细介绍了MybatisMapper.xml配置的sql语句与接口中方法绑定的具体细节,并分析了Mybatis中根据接口构建实例对象的背后逻辑。事实上,前几章的核心内容通过如下这张图就能概括。

在几章的介绍中,我们一直都在围绕使用Mybatis的四行代码进行分析。但这就结束了吗?当然不是!这四行代码是你"简单"使用Mybatis的极限,却不是Mybatis的极限。

使用Mybatis的四行代码

java 复制代码
  //<1> 加载配置文件
  InputStream is = Resources.getResourceAsStream("mybatis.xml");
  //<2> 创建sessionFactory对象
  sessionFactory = new SqlSessionFactoryBuilder().build(is);
  //<3> 获取sqlSession对象信息
  SqlSession session = factoy.openSqlSession();
  //<4> 构建映射器的代理对象
  UserMapper mapper = session.getMapper(UserMapper.class);
  // .....调用相关方法信息

事实上,这四行代码是Mybatis提供给开发者方便其快速上手Mybatis的。通过这样的编码,开发者就能实现接口方法和sql语句的绑定,进而获取到一个实现该接口的实例对象。进一步,用户调用接口中的方法将就能完成sql的执行。

Mybatis内部又是如何来执行这些sql语句的呢?别着急,这些内容都将在后续的文章都将会进行介绍。笔者将像剥洋葱一样,一层层的剥开潜藏在Mybatis身上的全部秘密

此时你可能会疑惑Mybatis中代码那么多,如果要分析Mybatissql执行的相关逻辑,应该从哪入手呢?

接下来不妨按着笔者的思路来逐一分析,看看笔者是如何来寻找Mybatissql执行的入口位置的,相信看到最后你一定会有一种"拨云见日"的感觉。

重新认识SqlSession

Mybatis流程分析(六): Mybatis中方法和sql语句的桥梁------MapperProxy我们曾提到:当调用Mybaits内部经过动态带来返回的实例对象中的方式时,其本质是从Configurtaion对象中获取缓存的MappedStatement对象,提取出其中的sql信息,然后将sql执行逻辑委托于SqlSession来进行执行。 具体来看,这部分代码逻辑如下:

java 复制代码
public class MapperMethod {

// .... 省略其他无关代码

  public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
     
      case SELECT:
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
        }
      // ....省略其他相似逻辑的代码
    return result;
  }


private void executeWithResultHandler(SqlSession sqlSession, 
                                        Object[] args) {
    // 相当于对sql内容进行封装
    MappedStatement ms = sqlSession.getConfiguration().
    Object param = method.convertArgsToSqlCommandParam(args);
    
    // 通过sqlSession中的select方法进行执行
    sqlSession.select(command.getName(), param, method.extractResultHandler(args));
  }

}

至于Mybatis内部是如何调用到MapperMethod中的executeWithResultHandler方法的,笔者在此便不再重复论述了。不了解其中调用逻辑的可以回看Mybatis流程分析(六): Mybatis中方法和sql语句的桥梁------MapperProxy中的相关内容。

简单来看,MapprProxy中的invoke方法会将执行sql的功能委托给MapperMethodInvoker。进一步,MapperMethodInvoker内部又会将处理逻辑委托给MapperMethod中execute()方法进行处理。

事实上,Mybatis中通过代理返回的实例对象,其增强逻辑本质就是交给MapperProxy来进行完成的。具体来看,增强逻辑本质就是在的MapperProxy中的invoke方法来完成的。

进一步,当调用Mybatis所返回的实例对象的内部方法时,其本质就是执行与方法绑定的sql语句。换言之,只要顺着MapperProxy中的invoke方法的调用链寻找,就一定能找到Mybatis中执行sql的相关逻辑。

更进一步,相信MyBatis中的 SqlSession 应该有一个更深刻的认识。其功能不仅仅只局限于会话管理对象生成,其内部更是提供了许多方法来执行 sql 的操作,这其中包括 select 方法。

至此,我们先前提出的问题其实已经有了答案。换言之,若要探究Mybatissql执行的相关逻辑,则SqlSession中的select方法就是我们分析这一问题入口

藏在select方法中的"秘密"

我们曾在Mybatis流程分析(二):配置处理,构建SqlSession工厂中提及过,在MybatisSqlSession为一个接口。而我们使用Mybatis时,其内部会为我们构建一个DefaultSqlSession对象来进行会话的管理。所以,如果要分析Sqlsessionselect方法的实现逻辑,我们重点关注其在DefaultSqlSession中的实现就可以了。

DefaultSqlSession#select

java 复制代码
public void select(String statement, Object parameter, 
                    RowBounds rowBounds, ResultHandler handler) {
     <1> 根据namespce+methodId获取对应的MappedStatement
    MappedStatement ms = configuration.getMappedStatement(statement);
    <2> 调用执行器中Executor中的query方法
    executor.query(ms, wrapCollection(parameter), rowBounds, handler);
    // .... 省略其他无关逻辑
 
}

可以看到,DefaultSqlSession中的select方法内部会做两件事:

  1. 根据传递的statmentId信息从Configuration中获取对应的MappedStatment对象;
  2. 将获取到的MappedStatment对象作为参数传递给 executor.query

细心的读者可能会注意到上述代码中所示的select方法其返回值为一个void,如果我们接口中方法的返回值类型为为一个实体对象,那这样不就出错吗?

但实际的结果却和预期相反,在使用Mybatis时并不会出现这样的bug。至于其中的原因,笔者在此先不给出相关解答,这个问题的答案我们留在分析ResultHandler的时候给予回答。

(注:DefaultSqlSession中存在select方法的多个重载版本,但其最终都会调用到上述这个版本的select方法)

总结

本文从MapperProxy中的invoke方法入手,逐一梳理invoke方法的调用逻辑,由浅入深的分析了Mybaits内部执行sql的语句的入口位置。具体来看,Mybatis中执行sql语句会委托给SqlSession中的select。进一步,sql语句的执行又将委托给Executor中的query方法。

换言之,Mybatissql语句的相关执行都是通过Executor来完成。事实上,MyBatis 中的 Executor 是一个核心组件,负责执行sql语句与数据库的交互。它扮演着连接数据库、执行sql语句、处理结果集等重要角色。而执行器------Executor也将在下一章进行讨论,敬请期待。

相关推荐
郑州光合科技余经理20 分钟前
PHP构建:支撑欧美澳市场的同城生活服务平台开发
java·开发语言·数据库·uni-app·php·排序算法·生活
章豪Mrrey nical7 小时前
前后端分离工作详解Detailed Explanation of Frontend-Backend Separation Work
后端·前端框架·状态模式
超级大只老咪7 小时前
数组相邻元素比较的循环条件(Java竞赛考点)
java
小浣熊熊熊熊熊熊熊丶8 小时前
《Effective Java》第25条:限制源文件为单个顶级类
java·开发语言·effective java
毕设源码-钟学长8 小时前
【开题答辩全过程】以 公交管理系统为例,包含答辩的问题和答案
java·eclipse
啃火龙果的兔子8 小时前
JDK 安装配置
java·开发语言
星哥说事8 小时前
应用程序监控:Java 与 Web 应用的实践
java·开发语言
派大鑫wink8 小时前
【JAVA学习日志】SpringBoot 参数配置:从基础到实战,解锁灵活配置新姿势
java·spring boot·后端
程序员爱钓鱼8 小时前
Node.js 编程实战:文件读写操作
前端·后端·node.js
xUxIAOrUIII8 小时前
【Spring Boot】控制器Controller方法
java·spring boot·后端