Mybatis 的整体架构分为三层,分别是基础支持层、核心处理层和接口层。基础支持层为核心处理层的功能提供了良好的支撑。

一、接口层


在不与 Spring 集成的情况下,使用 MyBatis 执行数据库的操作主要如下:

InputStream is = Resources.getResourceAsStream("myBatis-config.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
sqlSession = factory.openSession();

SqlSession 是 MyBatis 核心接口之一,能够让你执行命令,获取映射,管理事务。该接口中定义了 MyBatis 暴露给应用程序调用的API ,也就是上层应用与 MyBatis 交互的桥梁。接口层在接收到调用请求时,会调用核心处理层的相应模块来完成具体的数据库操作。MyBatis 提供了两个 SqlSession 接口的实现,如下,这里使用工厂模式,其中最常用的是 DefaultSqlSession 实现。
SqlSessionFactory 负责创建 SqlSession 对象,其中只包含了多个 openSession() 方法的重载,可以通过其参数指定事务的隔离级别、底层使用 Executor 的类型以及是否自动提交事务等方面的配置。在 SqlSession 中定义了常用的数据库操作以及事务相关操作:

package org.apache.ibatis.session;

import java.io.Closeable;
import java.sql.Connection;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.executor.BatchResult; public interface SqlSession extends Closeable { // 定位到具体的SQL,返回值为查询结果对象
<T> T selectOne(String statement); // 定位到具体的SQL,传入参数
<T> T selectOne(String statement, Object parameter); // 查询结果会有多条返回记录
<E> List<E> selectList(String statement); // 同上
<E> List<E> selectList(String statement, Object parameter); // 返回结果为Map
<K, V> Map<K, V> selectMap(String statement, String mapKey);
<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey);
<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds); // 返回游标对象
<T> Cursor<T> selectCursor(String statement);
<T> Cursor<T> selectCursor(String statement, Object parameter);
<T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds); // 查询结果有此处指定的ResultHandler 对象处理
void select(String statement, Object parameter, ResultHandler handler);
void select(String statement, ResultHandler handler);
void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler); // 执行插入语句
int insert(String statement);
int insert(String statement, Object parameter); // 执行修改语句
int update(String statement);
int update(String statement, Object parameter); // 执行删除语句
int delete(String statement);
int delete(String statement, Object parameter); // 提交事务
void commit();
void commit(boolean force); // 回滚事务
void rollback();
void rollback(boolean force); // 刷新到数据库
List<BatchResult> flushStatements(); // 关闭当前session
@Override
void close(); // 清空缓存
void clearCache(); // 获取Configuration 对象
Configuration getConfiguration(); // 获取 type 对应的mapper 对象
<T> T getMapper(Class<T> type); // 获取对应的数据库连接
Connection getConnection();
}

DefaultSqlSession 中的核心字段的含义:使用了策略模式,DefaultSqlSession   扮演了 Context 的角色,而将所有数据库相关的操作全部封装到 Executor 接口实现中,并通过 executor 字段选择不同的 Executor 实现。

private final Configuration configuration;// Configuration 配置对象
private final Executor executor; //底层以来的 Executor
private final boolean autoCommit; //是否自动提交事务
private boolean dirty; //当前缓存中是否有脏数据
private List<Cursor<?>> cursorList; //统一关闭游标对象

二、核心处理层


在核心处理层中实现了 MyBatis 的核心处理流程,其中包括 MyBatis 的初始化以及完成一次数据库操作的全部流程,如下:
【1】配置解析:在 MyBatis 初始化过程中,会加载 mybatis-config.xml 配置文件、映射配置文件以及 Mapper 接口中的注解信息,解析后的配置信息会形成相应的对象并保存到 Configuration 对象中。例如,定义的 <resultMap>节点会被解析成 ResultMap 对象,<result>节点会被解析成 ResultMapping 对象。之后,利用该 Configuration 对象创建 SqlSessionFactory 对象。待 MyBatis 初始化之后,开发人员可以通过初始化得到 SqlSessionFactory 创建 SqlSession 对象并完成数据库操作。
【2】SOL 解析与 scripting 模块:MyBatis 实现动态 SQL 语句的功能,提供了多种动态 SQL 语句对应的节点,例如,<where>节点、<if>节点、<foreach>节点等。通过这些节点的组合使用, 开发人员可以写出几乎满足所有需求的动态 SQL 语句。MyBatis 中的 scripting 模块会根据用户传入的实参,解析映射文件中定义的动态 SQL节点,并形成数据库可执行的 SQL 语句。之后会处理 SQL 语句中的占位符,绑定用户传入的实参。
【3】SOL 执行:SQL 语句的执行涉及多个组件,其中比较重要的是 Executor StatementHandler ParameterHandler ResultSetHandler(四大核心组件)。Executor 主要负责维护一级缓存和二级缓存,并提供事务管理的相关操作,它会将数据库相关操作委托给 StatementHandler 完成。StatementHandler 首先通过 ParameterHandler 完成 SQL 语句的实参绑定;然后通过 java.sql.Statement 对象执行SQL 语句并得到结果集;最后通过 ResultSetHandler 完成结果集ResultSet 的映射,得到结果对象并返回。如下展示了 MyBatis 执行一条 SQL 的过程:
【4】插件:MyBatis 自身的功能很强大,但并不能完美适应所有的场景,因此提供了插件接口,可以通过用户自定义的方式对 MyBatis 进行扩展。例如,可以拦截 SQL 语句并对其进行重写。

MyBatis 层级结构各个组件的介绍:
【1】SqlSession:它是 MyBatis 核心 API,主要用来执行命令,获取映射,管理事务。接收开发人员提供 Statement Id 和参数。并返回操作结果。
【2】Executor :执行器,是 MyBatis 调度的核心,负责 SQL 语句的生成以及查询缓存的维护。
【3】StatementHandler : 封装了JDBC Statement 操作,负责对 JDBC Statement 的操作,如设置参数、将 Statement 结果集转换成 List 集合。
【4】ParameterHandler : 负责对用户传递的参数转换成 JDBC Statement 所需要的参数。
【5】ResultSetHandler : 负责将 JDBC 返回的 ResultSet 结果集对象转换成 List 类型的集合。
【6】TypeHandler : 用于 Java 类型和 JDBC 类型之间的转换。
【7】MappedStatement : 动态 SQL 的封装
【8】SqlSource : 表示从 XML 文件或注释读取的映射语句的内容,它创建将从用户接收的输入参数传递给数据库的 SQL。
【9】Configuration: MyBatis 所有的配置信息都维持在 Configuration 对象之中。

三、基础支持层


【1】反射模块:该模块对 Java 原生的反射进行了良好的封装,提供了更加简洁的 API,方便上层调用,并且对反射操作进行了一系列优化,例如缓存类的元数据,提高了反射操作的性能。
【2】类型转换模块:MyBatis 为简化配置文件提供了别名机制,该机制是类型转化模块的主要功能之一。另一个功能是 JDBC类型与 Java 类型之间的转换,该功能在为 SQL 语句绑定实参以及映射查询结果集时都会涉及。在为 SQL 语句绑定实参时,会将数据由 Java 类型转化成 JDBC 类型;而在映射结果集时,会将数据由 JDBC 类型转换成 Java 类型。
【3】日志模块:无论在开发测试环境中,还是在线上生产环境中,日志在整个系统中的地位都是非常重要的。良好的日志功能可以帮助开发人员快速定位bug,也可以帮助运维人员快速定位性能瓶颈问题。目前 Java 世界中存在很多优秀的日志框架,例如 Log4j、slf4j等。MyBatis 作为一个设计优良的框架,除了提供详细的日志输出信息,还要能够集成多种日志框架。
【4】资源加载模块:资源加载模块主要是对类加载器进行封装,确定类加载器的使用顺序,并提供了加载类文件以及其它资源资源文件的功能。
【5】解析器模块:对 XPath 进行封装,为 MyBatis 初始化时解析 mybatis-config.xml 配置文件以及映射配置文件提供支持,为处理动态SQL 语句中的占位符提供支持。
【6】数据源模块:开源的数据源都提供了丰富的功能,比如连接池功能,检测连接状态等。选择优秀的数据源组件对于提升 ORM框架乃至整个应用的性能都有非常主要的帮助。MyBatis 自身提供了相应的数据源实现,也提供了与第三方数据源集成的接口。
【7】事务管理:MyBatis 对数据库中的事务进行了抽象,其自身提供了相应的事务接口和简单实现。在很多场景中,MyBatis 与Spring 框架集成,并由 Spring框架管理事务。
【8】缓存模块:优化性能时,优化数据库性能是非常重要的一个环节,而添加缓存则是优化数据库时最有效的手段之一。合理地使用缓存可以将一部分数据库请求拦截在缓存这一层,能够减少相当一部分数据库的压力。MyBatis 提供了一级缓存和二级缓存,而这两级缓存都是依赖于基础支持层中的缓存模块实现的。MyBatis 中自带的这两级缓存与 MyBatis 以及整个应用是运行在同一个JVM中的,共享同一块堆内存。如果这两级缓存中的数据量较大, 则可能影响系统中其他功能的运行,所以当需要缓存大量数据时,优先考虑使用Redis 、Memcache 等缓存产品。
【9】Binding 模块:在调用 SqlSession 相应方法执行数据库操作时,需要指定映射文件中定义的 SQL 节点,如果出现拼写错误,我们只能在运行时才能发现相应的异常。为了尽早发现这种错误,MyBatis 通过 Binding 模块将用户自定义的 Mapper 接口与映射配置文件关联起来,系统可以通过调用自定义 Mapper 接口中的方法执行相应的 SQL 语句完成数据库操作,从而避免上述问题。开发人员无需编写自定义 Mapper 接口的实现,MyBatis 会自动为其创建动态代理对象。在有些场景中,自定义 Mapper 接口可以完全代替映射配置文件,但有的映射规则和 SQL 语句的定义还是写在映射配置文件中比较方便,例如动态 SQL 语句的定义。

----关注公众号,获取更多内容----

MyBatis 整体架构【包含 SQL执行流程】的更多相关文章

  1. MySQL架构与SQL执行流程

    MySQL架构设计 下面是一张MySQL的架构图: 上方各个组件的含义如下: Connectors 指的是不同语言中与SQL的交互 Management Serveices & Utiliti ...

  2. MyBatis 源码篇-SQL 执行的流程

    本章通过一个简单的例子,来了解 MyBatis 执行一条 SQL 语句的大致过程是怎样的. 案例代码如下所示: public class MybatisTest { @Test public void ...

  3. MyBatis整体架构

    Mybatis整体架构 基础支持层 反射模块 Java中的反射很强大,但是还是需要封装的.MyBatis专门提供了反射模块,对元素的反射进行了封装,提供了简洁的API,对反射进行了优化,例如缓存了类的 ...

  4. 0807再整理SQL执行流程

    转自http://www.cnblogs.com/annsshadow/p/5037667.html MySQL架构总览->查询执行流程->SQL解析顺序   前言: 一直是想知道一条SQ ...

  5. MyBatis源码分析(二):MyBatis整体架构及原理

    一.Mybatis整体架构导图 二.Mybatis的核心组成 SqlSessionFactoryBuilder(构造器): 根据配置信息(XML)生成SqlSessionFactory工厂接口,构造器 ...

  6. Spark修炼之道(进阶篇)——Spark入门到精通:第九节 Spark SQL执行流程解析

    1.总体执行流程 使用下列代码对SparkSQL流程进行分析.让大家明确LogicalPlan的几种状态,理解SparkSQL总体执行流程 // sc is an existing SparkCont ...

  7. Hive SQL执行流程分析

    转自 http://www.tuicool.com/articles/qyUzQj 最近在研究Impala,还是先回顾下Hive的SQL执行流程吧. Hive有三种用户接口: cli (Command ...

  8. 步步深入:MySQL架构总览->查询执行流程->SQL解析顺序

    前言: 一直是想知道一条SQL语句是怎么被执行的,它执行的顺序是怎样的,然后查看总结各方资料,就有了下面这一篇博文了. 本文将从MySQL总体架构--->查询执行流程--->语句执行顺序来 ...

  9. 深入浅出Mybatis系列(十)---SQL执行流程分析(源码篇)

    最近太忙了,一直没时间继续更新博客,今天忙里偷闲继续我的Mybatis学习之旅.在前九篇中,介绍了mybatis的配置以及使用, 那么本篇将走进mybatis的源码,分析mybatis 的执行流程, ...

  10. MySQL架构总览->查询执行流程->SQL解析顺序

    Reference:  https://www.cnblogs.com/annsshadow/p/5037667.html 前言: 一直是想知道一条SQL语句是怎么被执行的,它执行的顺序是怎样的,然后 ...

随机推荐

  1. LCP 34. 二叉树染色

    class Solution: def maxValue(self, root: TreeNode, k: int) -> int: def dfs(root): # 空节点价值全为0 res ...

  2. 接口自动化(TestNG)

    数据驱动概念: 用户输入输出数据来判断测试用例是否通过从而验证需求的测试. 一.接口自动化框架搭建(TestNG数据驱动) ---parameter 关键代码: <?xml version=&q ...

  3. Java断言语句

    ​ 断言语句在调试代码阶段非常有用,断言语句一般用于 程序不准备通过捕获异常来处理的错误,例如,当发生某个错误时,要求程序必须立即停止执行.在调试代码阶段让断言语句发挥作用,这样就可以发现一些致命的错 ...

  4. Mybatis框架中 collection 标签 和 association标签中关于 columnPrefix 属性的底层逻辑

    columnPrefix的作用是给column自动拼接上前缀, 已知多重嵌套的collection 和 association的columnPrefix属性的值是会叠加的 <associatio ...

  5. el-table 固定列错位问题

    1. 问题描述:el-table使用固定列时,使用keep-alive后页面切换导致该列错位. 2. 解决方法:使用el-table的doLayout方法对表格进行重新布局 activated() { ...

  6. c++学习6 指针变量

    一 指针变量的定义 *是用来修饰指针变量的,通常情况下我们定义的手法都是"类型名"+"*"+"指针变量名称". 有一种简单无脑的" ...

  7. ES7-ES12总结篇

    脑图模式       插入 ES7-ES12  ES7  Array.prototype.includes()   includes() 方法用来判断一个数组是否包含一个指定的值,如果包含则 ...

  8. pandas的groupby.apply和直接apply效果是不一样的

    GroupBy.apply(func, *args, **kwargs)[source] Apply function func group-wise and combine the results ...

  9. Hadoop高可用集群存在的一些共性问题

    Hadoop高可用集群存在的一些共性问题 1.NameNode 偶然性挂掉 问题原因: 用群启脚本启动HA集群,启动过程中NameNode要依赖于JournalNode,所以在启动过程中, ​ Nam ...

  10. Think in UNL其一

    书中提到世界本质上为离散的,由一个一个对象组成.其实这个观点并不难理解,因为在公元前5世纪芝诺就有了类似的思考,著名的阿基里斯悖论早已经被推翻,现代物理学已经证明了时间和空间不是可以无限分割的,所以总 ...