MyBatis的解析和运行原理

MyBatis运行过程分为两步:

  1. 读取配置文件缓存到Configuration对象,用以创建SqlSessionFactory;
  2. SqlSession的执行过程

1. 构建SqlSessionFactory过程

SqlSessionFactory是MyBatis的核心类之一,提供创建MyBatis的核心接口SqlSession,所以要先创建SqlSessionFactory,因此要提供配置文件和相关参数。MyBatis使用Builder模式创建SqlSessionFactory,可以通过SqlSessionFactoryBuilder构建,分为两步:

  • 通过 org.apache.ibatis builder. xml .XMLConfigBuilder 解析配置的 XML 文件,将读取的内容存入org.apache.ibatis.session.Configuration类对象中。Configuration采用单例模式,MyBatis配置内容都存放在这个单例对象中,以便后续将内容读出。
  • 使用Configuration对象创建SqlSessionFactory。MyBatis中的SqlSessionFactory是一个接口,而不是一个实现类,因此MyBtais提供一个默认的实现类org.apache,ibatis.session.defaults.DeafultSqlSessionFactory。
    用XMLConfigBuilder解析XML源码:
    在这里插入图片描述
    在这里插入图片描述typeHandler被注册到typeHandlerReigistry对象中,其定义是放在XMLConfigBuilder的父类BaseBuilder中。
    BaseBuilder类的源码:
    在这里插入图片描述
    typeHandlerRegistry对象实际是Configuration单例的一个属性,因此可以通过Configuration单例拿到typeHandlerRegistry对象,进而得到所注册的typeHandler。

1.构建Configuration
SqlSessionFactory构建中,Configuration非常重要,其作用是:

  • 读入配置文件,包括基础配置的XML和映射器XML(/注解)
  • 初始化一些基础配置,如MyBatis别名,一些重要的类对象(插件、映射器、Object工厂、typeHandlers对象)
  • 提供单例,为后续创建SessionFactory服务,配置参数
  • 执行一些重要对象的初始化方法

Configuration通过XMLConfigBuilder构建,首先他会读出所有XML配置的信息,然后将他们解析并保存在Configuration单例中。其进行如下初始化:
• properties 全局参数
• typeAliases 别名
• Plugins 插件
• objectFactory 对象工厂。
• objectWrapperFactory 对象包装工厂。
• reflectionFactory 反射工厂。
• settings 环境设置。
• environments 数据库环境
• databaseldProvider 数据库标识
• typeHandlers 类型转换器
• Mappers 映射器
2.构建映射器的内部组成
当XMLConfigBuilder解析XML,会将每个SQL和其配置的内容保存起来。在Mybatis的一条SQL和其相关的配置信息是由3个部分组成,分别是MappedStatement、SqlSource和BoundSql。

  • MappedStatement 作用是保存1个映射器节点( selectlinse deletelupdate)的内容。它是1个类,包括许多我们配置的 SQL SQL的id 、缓存信息、 resultMap、parameterType、resultType、resultMap、languageDriver 等重要配置内容。还有sqlSource,通过读取它来获得某条SQL配置的所有信息。
  • SqlSource提供BoundSql对象,是MappedStatement的一个属性。其是一个接口,而不是一个实现类。其实现类有:DynamicSqlSource、 ProviderSqISource、RawSqlSource、StaticSqlSource。其作用是根据上下文和参数解析生成需要的SQL。这个接口只定义了个接口方法getBoundSql(parameterObject),使用它就可以得到BoundSql对象。
  • BoundSql是一个结果对象,也就是SqlSource通过对SQL和参数的联合解析得到的SQL和参数,它是建立 SQL 参数的地方,有3个常用的属性:sql、parameterObject、parameter Mappings 。

映射器的内部组成:
在这里插入图片描述MappedStatement 对象涉及的东西较多,一般不去修改它,因为容易产生不必要的错误。SqlSource是个接口,它的主要作用是根据参数和其他的规则组装SQL。对于最终的参数和 SQL 都反映 BoundSql类对象上,在插件中往往需要拿到它进而可以拿到当前运行的 SQL和参数,从而对运行过程做出必要的修改,来满足特殊的需求,这便是 MyBatis 插件提供的功能。
BoundSql提供三个主要的属性:parameterMappings、parameterObject和sql。

1.parameterObject 参数本身可以传递简单对象、POJO或者Map、@Param 注解的参数。
(1).传递简单对象,包括int、String、float、double等。当传递int类型时, MyBatis把参数变为 Integer 对象传递,类似的 long String float double 如此。
(2).传递 POJO 或者 Map, parameterObject 是传入的 POJO 或者 Map
(3).传递多个参数,如果没有@Param 注解,那么 MyBatis 会把parameterObject 变为Map<String, Object> 对象,其键值的关系是按顺序来规划 的, 类似于{ 1: pl, "2":p2,“ 3”:p3……,“paraml”:pl,“param2":p2,“param3":p36 ...... }这样的形式,所以在编写时可以使用#{paraml }或者#{1}去引用第1 个参数。
(4)使用@ Param 注解, MyBatis 就会把 parameterObject 变为一个Map <String, Object>对象,类似于没有@Param 注解,只是把其数字的键值置换成@Param 注解键值。

2.parameterMappings是一个List,它的每一个元素都是ParameterMapping对象。对象会描述参数,参数包括属性名称、表达式, javaType、jdbcType、 typeHandler 等重要信息,一般不需要去改变它。通过它就可以实现参数和 SQL 结合,以便 Prepared Statement 能够通过它找到 parameterObject 对象的属性设置参数,使得程序能准确运行。
3.sql属性就是书写在映射器里面的被 SqlSource 解析后的 SQL 。

3.构建SqlSessionFactory
有了Configuration对象,然后构建SqlSessionFactory:
在这里插入图片描述
MyBatis 会根据文件流先生成Configuration对象,进而构建SqlSessionFactory 对象。真正的难点在于构建Configuration对象。

2. SqlSession运行过程

1.映射器的动态代理
有如下一行代码:
在这里插入图片描述
MyBatis中的getMapper方法:
在这里插入图片描述
其使用了Configuration对象的getMapper方法,获取对应的接口对象。有如下方法:
在这里插入图片描述
该方法使用了映射器的注册器Mapperegistry·来获取对应的接口对象。
在这里插入图片描述
首先它判断是否注册 Mapper ,如果没有则会抛出异常信息,如果有,就会启用MapperProxyFactory 工厂来生成一个代理实例,为此再追踪加粗代码的实现:
在这里插入图片描述
在这里插入图片描述
注意加粗的代码, Mapper 映射是通过动态代理来实现的。这里可以看到动态代理对接口的绑定,它的作用就是生成动态代理对象(占位),而代理的方法则被放到了 MapperProxy类中。MapperProxy源码:
在这里插入图片描述
invoke方法的逻辑:
当Mapper是一个JDK动态代理对象,则就会运行到invoke方法里,首先判断是否是一个类,Mapper是一个接口,因此判定失败。随后生成MapperMethod对象,通过cacheMapperMethod方法对其初始化。最后执行execute方法,将SqlSession和当前运行的参数传递进去。execute方法如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
加粗的代码 MapperMethod 类采用命令模式运行,根据上下文跳转可能跳转到许多方法中,通过源码我们清楚,实际上它最后就是通过 SqlSession 对象去运行对象的 SQL 而己,其他的增、删、查、改也是类似这样处理的。
MyBatis只用Mapper接口就能运行的原因:
Mapper的 XML 文件的命名 空间对应的是这个接口的全限定名,而方法就是那条 SQL的id ,这样 MyBatis 就可以根据全路径和方法名,将其和代理对象绑定起来。通过动态代理技术,让这个接口运行起来,而后采用命令模式。最后使用 SqI Session 接口的方法使得它能够执行对应的 SQL 。
2.SqlSession的四大对象
映射器就是个动态代理对进入到了 MapperMethod的execute方法,它经过简单地判断就进入了 Sq!Session的delete、update、insert、select 等方法。SqlSession 的执行过程是通过Executor、StatementHandler、ParameerHandler ResultSetHandler 来完成数据库操作和结果返回的。

  • Executor为执行器,由它调度 StatementHandler、ParameterHandler、 ResultSetHandler等来执行对应的 SQL 。
  • StatementHandler的作用是使用数据库的Statement ( PreparedStatement执行操作,它是四大对象的核心。
  • ParameterHandler是用来处理 SQL 参数的
  • ResultSetHandler是进行数据集( ResultSet 的封装返回处理的

(1)Executor
Executor 是一个执行器。 SqlSession 其实是门面,真正干活的是执行器,它是真正执行 Java 和数据库交互的对象,所以它十分重要。
执行器提供了查询( query )方法、更新( update )方法和相关的事务方法, 这些和其他框架并无不同。
执行器的生成:
在这里插入图片描述MyBatis 将根据配置类型去确定需要创建哪一种Executor ,它的缓存则用CachingExecutor 进行包装 Executor。
(2)StatementHandler(数据库会话器)
专门处理数据库会话:
在这里插入图片描述
创建的真实对象是 RoutingStatementHandler 的对象,实现了接口StatementHandler。RoutingStatementHandler 不是真实的服务对象 ,它是通过适配模式来找到对应的StatementHandler 来执行的。在初始化 RoutingStatementHandler 象时,它会根据上下文环境决定 建哪个具体的StatmentHandler 对象实例。生成StatementHandler:
在这里插入图片描述

在这里插入图片描述
其定义了一个对象的配适器-delegate,是一个StatementHandler接口对象,然后构造方法根据配置来配饰对应的StatementHandler对象。作用是给3个接口对象的使用提供一个统一的配适器。Executor执行查询时会执行 StatementHandler 的prepare、 parameterize、 query方法。
执行prepare方法:
在这里插入图片描述
在这里插入图片描述instantiateStatement方法是对 SQL 进行了预编译,然后做些基础配置,比如超时、获取的最大行数等的设置。 Executor 会调用它的 parameterize()方法去设置参数。

在这里插入图片描述
执行SQL返回结果:

在这里插入图片描述
查询 SQL 的执行过程:Executor 先调用 StatementHandler的prepare()方法预编译SQL,同时设置些基本运行的参数。然后用 parameterize() 方法启用 ParameterHandler设置参数,完成预编译,执行查询, update()也是这样的 。如果是查询 MyBatis 会使用ResultSetHandler 封装结果返回给调用者。
(3).ParameterHandler-参数处理器
MyBatis 是通过 ParameterHandler 对预编译语句进行参数设置的,它的作用是完成对预编译参数的设置。接口如下:
在这里插入图片描述getParameterObject()方法的作用是返回参数对象。
setParameters() 方法的作用是设置预编译 SQL 语句的参数。
(4)ResultSetHandler-结果处理器
ResultSetHandler 是组装结果集返回的,接口如下:
在这里插入图片描述
handleOutputParameters() 方法是处理存储过程输出参数的,handleResultSets() 方法,它是包装结果集的。MyBatis 提供了
DefaultResultSetHandler 的实现类,在默认情况下都是通过这个类进行处理的。然后通过 typeHandler和ObjectFactory 进行组装结果再返回。
3.SqlSession运行总结
内部运行如下所示:
在这里插入图片描述SqlSession 是通过执行器 Executor 调度 StatementHandler 来运行的。StatementHandler经过3步:

  • prepared 预编译 SQL
  • parameterize 设置参数
  • query/update 执行 SQL

parameterize 是调用 parameterHandler 的方法设置的,而参数是根据类型处理器typeHandler处理的。query/update 方法通过 ResultSetHandler 进行处理结果的封装,如果是update 语旬,就返回整数;否则就通过 typeHandler 处理结果类型,然后用 ObjectFactory提供的规则组装对象,返回给调用者。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值