zoukankan      html  css  js  c++  java
  • MyBatis 源码篇-SQL 执行的流程

    本章通过一个简单的例子,来了解 MyBatis 执行一条 SQL 语句的大致过程是怎样的。

    案例代码如下所示:

    public class MybatisTest {
    
        @Test
        public void selectByPrimaryKey() throws IOException {
            // 3
            StudentDao studentDao = getSqlSession().getMapper(StudentDao.class);
            // 4
            Student student = studentDao.selectByPrimaryKey(1L);
            System.out.println(student);
        }
    
        /**
         * 获取SqlSession
         * 
         * @return
         */
        private SqlSession getSqlSession() throws IOException {
            // 1
            InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
            // 2
            return sqlSessionFactory.openSession(true);
        }
    }

    Configuration

    第一步,通过资源加载模块加载配置文件,解析器模块解析 XML 文件,生成 Configuration 对象。

    源码内容参考:org.apache.ibatis.session.SqlSessionFactoryBuilder#build(java.io.InputStream, java.lang.String, java.util.Properties) 方法

    深入 parse() 方法可以查看配置文件的具体解析过程,以及如何生成 Configuration 对象。

    Configuration 对象中缓存了 mybatis-config.xml 配置文件以及映射配置文件的所有内容。

    SqlSession

    第二步,通过 SqlSessionFactory 创建 SqlSession,SqlSession 是 MyBatis 暴露给外部使用的统一接口层,所有和数据库打交道的操作都通过 SqlSession 这层。

    下面通过时序图描述 SqlSession 对象的创建流程:

    MapperProxy

    第三步,通过 SqlSession 获得 StudentMapper 对象,为了便于理解,下面通过时序图描述 Mapper 对象的获取流程。

    MapperRegistry 是 Configuration 的一个属性,MapperRegistry 缓存了 MapperProxyFactory 的 Map 集合,也就是说在解析完配置文件后,knownMappers 集合数据已经在 Configuration 对象中存在了。

     

    问题一:为什么 StudentMapper(接口) 可以调用方法?

    通过断点调试来看看 StudentMapper 的真实对象是什么:

    MapperProxy 类的代码如下:

    MapperProxyFactory 的 newInstance 方法实现代码如下:

    通过上面的源码内容,可以得出如下结论:

    • StudentMapper 的真实对象是 MapperProxy;
    • MapperProxy 继承 InvocationHandler,实现 invoke 方法;
    • MapperProxyFactory 的 newInstance 方法,通过 JDK 动态代理的方式创建了一个 MapperProxy 的代理类;

    MyBatis 的 Mapper 是通过动态代理实现的,调用 Mapper 的任何方法都会执行 MapperProxy 的 invoke 方法。

    MyBatis 使用的动态代理和通常的动态代理有点区别,没有实现类,只有接口。

    动态代理类图结构如下所示:

    MyBatis 动态代理类图结构如下所示:

    selectByPrimaryKey

    第四部,执行 selectByPrimaryKey 查询学生信息。在第8行代码上面打上断点,调试选择“step into”,进入子函数内部,调用 org.apache.ibatis.binding.MapperProxy#invoke 方法。

    MapperMethod 通过如下方式创建。

    • mapperInterface:interface com.yjw.mybatis.dao.StudentMapper;
    • method:invoke 方法中传进来的 method 类;
    • Configuration:MyBatis 的核心类,所有配置信息都存在该类中;

    接着执行 mapperMethod.execute(sqlSession, args) 方法。

    接下来还是走到 SqlSession 类中,调用 selectOne 方法。继续往下执行,会执行 Executor 的 query 方法。

    通过上面的分析,简单总结一下,我们可以抽象出 MyBatis 在执行一条 SQL 查询的过程中涉及到的主要类:Configuration、SqlSession、MapperProxy、Exector,根据这些类画出如下 MyBatis 执行 SQL 的时序图:

    • 第一步是获取 MapperProxy 代理对象;
    • 第二步是根据获取的代理对象,执行查询操作;

    Exector

    SqlSession 中的 JDBC 操作部分最终都会委派给 Exector 实现,接着上面的断点往下执行,进入 Exector 的 query 方法。

    下面通过时序图描述 Exector 的执行流程,真实的调用链路类比较多,这里简化了调用链路,省略了一些装饰类、代理类,便于理解:

    根据 Exector 执行的时序图,可以抽象出的主要类是:SqlSession、Exector、StatementHandler、ParameterHandler、ResultSetHandler。

    StatementHandler 接口是 MyBatis 的核心接口之一,它是 Exector 接口实现的基础。StatementHandler 的主要功能很多,例如创建 Statement 对象,为 SQL 语句绑定实参,执行 SQL 语句,将结果集映射成结果对象。

    StatementHandler 类中包含了 ParameterHandler 和 ResultSetHandler 的属性。ParameterHandler 的主要功能是为 SQL 语句绑定实参,也就是使用传入的参数替换 SQL 语句中的“?”占位符。ResultSetHandler 的主要功能是将结果集映射成结果对象。

    参考 BaseStatementHandler 类:org.apache.ibatis.executor.statement.BaseStatementHandler

    结论

    根据上面的分析,抽象出的主要类有:Configuration、SqlSession、MapperProxy、Exector、StatementHandler、ParameterHandler、ResultSetHandler。

    MyBatis 源码篇

  • 相关阅读:
    [Redux] Extracting Container Components (FilterLink)
    [Regular Expressions] Introduction
    [Javascript] Web APIs: Persisting browser data with window.localStorage
    [Javascript] The JSON.stringify API
    [Redux] Extracting Presentational Components -- TodoApp
    [Redux] Extracting Presentational Components -- Todo, TodoList
    [Redux] Extracting Presentational Components -- Footer, FilterLink
    [Redux] Extracting Presentational Components -- AddTodo
    [Javascript] Task queue & Event loop.
    吸尘器:吸尘器
  • 原文地址:https://www.cnblogs.com/yinjw/p/11757349.html
Copyright © 2011-2022 走看看