Mybatis的执行流程和相关核心对象的介绍

从这篇博客开始,就会陆续记录我学习Mybatis源码的过程和心得。
先喝一碗鸡汤壮壮胆,首先我觉得做一件事首先要清楚自己做这件事的目的。不然做这件事过程中会很容易放弃,做完之后也不会有太多收获。
那么我学习Mybatis源码的目的就是

  1. 了解并学习大神写代码的风格,让自己写出的代码看起来不那么幼稚。
  2. 锻炼自己的心态,让自己不惧怕源码,平时的开发中如果任意框架的源码中报出异常,有能力通过其源码大致知道问题所在,锻炼自己主动找错和解决问题的能力,不总依赖百度和google。
  3. 学习源码中用到的设计模式,平时接触的设计模式都是其它博客列举的非常傻白甜的例子,而源码中的设计模式是非常直接且实际的应用,多体会其它人的思想。
  4. 最后才是清楚Mybatis源码的执行流程,其主要功能的设计思想和执行流程。必要时候可以结合自己的业务扩展其功能。

其中1,2,3是最主要的目的。时间久了,框架总是会随着业务变化,但自己的水平和能力才是熟悉和适应新框架的主要方式,以不变应万变。

好了,不废话了,进入正题。
阅读Mybatis源码到什么程度为止?我是读到最原始的JDBC处为止,不会再去往JDBC源码去研究。
OK,这篇博客主要介绍Mybatis对查询语句的执行流程,介绍在执行流程中所用的到Mybatis对象的作用,目的是对Mybatis有一个大致的理解,后续再一点一点拨开云雾,点到JDBC的执行流程。

Mybatis的基本应用

Mybatis的基本使用这里就不多说了,推荐一个Mybatis的官方网站吧。这上面有当前版本几乎Mybatis的所有使用说明,学习源码前还是有一定必要去看一看。不要听其它博客非要比较中英文优劣,适合自己且能达到自己目的就好。
Mybatis中文官方网站
这上面有很多功能我平时也没用过,不过也不耽误。基本的CRUD,TypeHandler,Plugin等会用就可以了,读源码的时候就会有种熟悉的感觉。Mybatis不像Spring那么复杂,源码到处都是没用过的注解,不知所以的类。

Mybatis的执行流程

准备阶段

在这里插入图片描述
Mybatis执行Sql的准备阶段,其实核心就是通过SqlSessionFactoryBuilder去读取Mybatis-config.xml这个配置文件,将其转换为一个Node根节点,其内部通过XMLConfigBuilder去解析这个Node根节点,依次遍历子节点,然后解析出的配置信息及mapper信息全部存储到Configuration中。SqlSessionFactoryBuilder可以创建一个SqlSessionFactory,用于产生SqlSession,SqlSession是Mybatis的顶级接口,包含着CRUD的各种方法。SqlSession会根据接口创造一个MapperProxy的代理类,这就是为什么我们使用接口就可以执行SQL的原因。

先说下配置文件,配置文件的节点都有什么呢?
打开其mybatis-3-config.dtd文件即可看到。
主要配置就是下面的部分,顺序一定不要写乱,Mybatis会对其进行检查。

<!ELEMENT configuration (properties?, settings?, typeAliases?, typeHandlers?, objectFactory?, objectWrapperFactory?, reflectorFactory?, plugins?, environments?, databaseIdProvider?, mappers?)>

SqlSessionFactoryBuilder
SqlSessionFactoryBuilder的生命周期就是初始化解析xml配置过程中,整个Mybatis执行中只会产生一个对象。其作用除了解析出Configuration外,还有构建SqlSessionFactory的作用,一旦构建SqlSessionFactory后,就没有存在的价值了。

SqlSessionFactory
SqlSessionFactory的生命周期是可以一直存在的,其作用如其类名一样,就是产生一个SqlSession的工厂,整个应用期间存在一个SqlSessionFactory对象即可,它可以创建多个SqlSession。
SqlSessionFactory是一个接口,其内部实现为DefaultSqlSessionFactory。维护着SqlSessionFactoryBuilder解析出来的Configuration对象。

SqlSession
按照Mybatis的官网来说,SqlSession这个对象生命周期属于每个线程,也就是说每个线程都可以从SqlSessionFactory中获取一个SqlSession对象。SqlSession是Mybatis中的顶级接口,其中有Mybatis的执行器Executor和Configuration对象,包含了CRUD各种方法以及事务提交和回滚方法。默认实现为DefaultSqlSession,属于Mybatis执行sql的管理者,实际执行sql依赖Executor执行器,需要的sql相关信息从Configuration中获取。

Configuration
Configuration的生命周期是整个应用期间,应用全程只会维护这一个对象,是Mybatis的核心类,存储着Mybatis执行过程中的所有需要的信息,也是XML配置的所有信息的存储对象。每次执行sql都会从其取出对应的sql信息,交给Sql执行器执行。几乎在后续的每个Mybatis构建的对象中都会存在这个实例变量。

MapperProxy
MapperProxy的生命周期同SqlSession,因为它由SqlSession通过JDK的动态代理创建。它就是我们的Mapper接口的代理逻辑类,实现了InvocationHandler这个接口,重写了invoke方法。每次我们调用Mapper接口的方法,实际就是调用MapperProxy的invoke方法,在这个方法内,Mybatsi再执行其它逻辑,进行增删改查操作。

执行阶段

在这里插入图片描述
执行阶段相对麻烦,上图仅仅是列出了主要的执行流程中的对象。

  1. 首先就是当我们的Mapper接口调用mapper方法的时候,本质就是MapperProxy调用其invoke方法,此方法内部会根据此mapper方法签名创建一个MapperMethod对象,当然所需的参考数据都是从Configuration中获取的。MapperMethod中的SqlCommand对象表示这个方法具体是CRUD中哪一种操作,具体的操作在初始化时都能解析出来。
  2. 然后就是MapperMethod根据SqlCommand的操作种类,选择调用SqlSession的具体执行方法,这里主要说Select操作。它会调用SqlSession的Select方法,SqlSession的身份算是sql执行的发布命令者,它内部维护者Executor对象(真正的干活的人),SqlSession会创建出MapperStatement对象给Executor使用,MapperStatement对象有这个mapper方法的各种信息,包括sql语句中的相关信息,缓存信息等等。这一系列准备最终都会交给Executor对象,由Executor对象去真正的做sql查询的操作。
  3. Executor会根据SqlSession准备的MapperStatement对象,再获取相关的一系列对象,由这些对象去配合自己执行sql语句。它会让StatementHandler对象去预编译sql语句,紧接着让ParameterHandler对象去处理每个查询的参数类型转换操作,再让StatementHandler去真正的和数据库打交道(内部是用JDBC的操作和数据库交互),让ResultSetHandler去处理查询数据库后,返回的数据的类型转换操作,这一切做完后,Executor这个大管家就会根据初始化时交待的配置信息,有选择的将查询结果进行一级缓存或者二级缓存,最后将结果依次返回给用户。

下面还是介绍一下这个执行流程中做出贡献的Mybatis对象吧。
MapperProxy大兄弟就不说了,前面已经介绍过了。

MapperMethod
MapperMethod在Mybatis中被做成了延迟加载并且缓存起来,第一次执行mapper方法时,会创建这个对象,后续再次执行相同的方法就会从MapperProxyFactory中获取,MapperProxyFactory内维护了一个map,存放着MapperMethod对象。这么说来,MapperMethod被Mybatis设计成了无状态对象,任意时候的线程通过不同的SqlSession执行sql操作,都会使用相同的MapperMethod对象。它的作用其实就是根据内部维护的SqlCommand(增删改查)选择不同的SqlSession操作。

MappedStatement
MappedStatement是初始化时根据Mapper接口和xml解析出的每个方法的相关信息,存储在Configuration中。内部维护着所有关于执行的sql所需要的配置数据,包括动态sql信息,Cache缓存对象,是否需要缓存查询结果,sql语句的参数映射关系等数据。每次mapper方法都会有个此对象,每次执行sql操作后,都有可能再次修改其中的某些信息,比如缓存信息。此对象是执行sql的核心对象。

Executor
Executor是Mybatis的执行器,真正的去处理sql操作的对象,被维护在SqlSession中,生命周期同SqlSession。这个对象用了装饰者模式,套用了很多层对象,最底层是默认是SimpleExecutor,第二层可以被CachingExecutor包装。它的作用就像一个地主家的大管家,对上听从SqlSession的命令,对下要发号施令去指挥其他下人去做不同的事,完成命令即可,有时候还会偷个懒,比如缓存一下数据,让下人们歇息歇息。

BoundSql
此对象由MappedStatement中获取,内部存储有这次CRUD操作所用到的sql语句,sql语句中用到的参数映射关系,以及可能用到的参数等信息。

CacheKey
CacheKey的意思如同其名字,就是一个缓存的名字,维护在Executor(SqlSession中的对象)中的map里。既然是缓存的名字,那Mybatis肯定不会让它和其它缓存重复了,Mybatis会用MappedStatement的id(mapper方法的全路径限定名),sql语句,sql语句用到的参数等信息做一个hash计算,结果作为这个CacheKey的唯一识别,那如果恰巧有人完全一样了怎么办?哈哈,这不就是一级缓存了么!!!直接把本地缓存map的val数据给那个重复的人喽!一级缓存是SqlSession级别的。

Cache
Cache看这名字是一个实际的缓存,不像CacheKey那样是一个key。它被维护在MappedStatement中,摊牌了,它其实就是二级缓存,因为MappedStatement维护在Configuration中,而Configuration的生命周期是整个应用,所以说二级缓存是Application级别的。

StatementHandler
StatementHandler是比较重要的一个类,内部维护着ParameterHandler和ResultSetHandler,它可以创建数据库连接Connation,调用Connation预编译sql,获取PrepareStatement对象。属于Executor手下的大哥。

ParameterHandler
ParameterHandler的作用是处理sql执行前,sql语句中的参数的类型转换处理。

ResultSetHandler
ResultSetHandler的作用是处理sql执行后,从PrepareStatement对象中获取ResultSet,也就是执行结果集,对结果集的数据类型进行处理。

TypeHanlder
这个就是类型转换器,被ParameterHandler和ResultSetHandler所使用的对象,内部有处理类型的方法。我们可以自定义TypeHanlder给业务代码使用。

以上就是Mybatis的执行流程和执行流程中所设计的核心对象,下面贴上一张流程图吧,出自是一位大神的博客,本人参考了它的Mybatis的讲解去学习源码的。
它的博客质量很高,也推荐你们去看看。
《深入理解mybatis原理》 MyBatis的架构设计以及实例分析

在这里插入图片描述
好了,本篇文章主要讲的就是Mybatis的大体执行流程和相关对象的介绍。先整体的去了解Mybatis,有一个初步的认识,后续再看源码也就相对容易了。文中如果有错误的地方,还请指出或评论交流,一起提高技术,结对编程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值