MyBatis源码-深入理解MyBatis Executor的设计思想

2021-08-17 11:41:45 浏览数 (1)

Pre

如果MyBatis的基础用法还不熟悉,31篇入门博客拿走不谢

戳戳戳 —> https://blog.csdn.net/yangshangwei/category_7205317.html


JDBC的执行过程

MyBatis 半自动的ORM框架 ,归根到底底层还是用的JDBC来访问数据库 , 所以有必要先回顾一下JDBC的执行过程

JDBC Demo

【演示Table 】


【演示Code】

代码语言:javascript复制
public class JdbcTest {
    public static final String URL = "jdbc:mysql://127.0.0.1:3306/o2o?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT+8&useSSL=false";
    public static final String USERNAME = "root";
    public static final String PASSWORD = "root";
    private Connection connection;

    @Before
    public void init() throws SQLException {
        // 第一步 获取连接
         connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
    }

    @After
    public void over() throws SQLException {
        connection.close();
    }

    @Test
    public void jdbcTest() throws SQLException {
        // 第二步  预编译  & 设置参数 
        String sql = "SELECT * FROM tb_area WHERE `area_name`=?";
        PreparedStatement sql1 = connection.prepareStatement(sql);
        sql1.setString(1,"北京");
        // 第三步 执行SQL
        sql1.execute();
        // 第四步 获取返回结果
        ResultSet resultSet = sql1.getResultSet();
        while (resultSet.next()) {
            System.out.println(resultSet.getString(3));
        }
        resultSet.close();
        sql1.close();;
    }
    
}

【执行结果】


【JDBC执行步骤总结】

无非就是下面几步

  1. 获取连接
  2. 预处理SQL ,设置参数等
  3. 执行SQL
  4. 获取返回结果

Mybatis既然是JDBC的封装框架, 那自然要处理 预处理这一步 ,所以有必要了解下JDBC中的Statement 接口


JDBC Statement 接口

整体接口和类的关系图如下

这里重点说一下 Statement 接口 ,通过该组件来发送对应的SQL与参数 .

它有三种类型:分别是 Statement,PreparedStatement和CallableStatement 接口, 继承关系如上,

【Statement接口】

  • 普通的不带参的查询SQL
  • 支持批量更新,批量删除

【PreparedStatement接口】

  • 继承自Statement接口
  • 可变参数的SQL,编译一次,执行多次,效率高
  • 安全,有效防止Sql注入等问题
  • 支持批量更新,批量删除

【CallableStatement接口】

  • 继承自PreparedStatement接口
  • 支持带参数的SQL操作
  • 支持调用存储过程,提供了对输出和输入/输出参数(INOUT)的支持

除了常见的接口方法, Statement 中还有2个非常规方法需要关注下,因为后续在MyBatis中源码会有体现。

  • addBatch: 批处理操作,将多个SQL合并在一起,最后调用executeBatch 一起发送至数据库执行
  • setFetchSize:设置从数据库每次读取的数量单位。该举措是为了防止一次性从数据库加载数据过多,导致内存溢出。(MySQL不支持 ,Oracle支持)

MyBatis执行过程

推荐使用鲁班大叔的源码地图来梳理MyBatis的源码执行过程,更直观易懂 。 ------->戳这里<----------

四大组件

每个组件的作用如下:

  • 接口代理: 简化对MyBatis使用,底层使用动态代理实现
  • Sql会话: 提供增删改查API, 本身不做业务逻辑的处理,所有处理都会交给执行器Executor。这是一个典型的门面设计模式
  • 执行器: 核心作用是处理SQL请求、事务管理、维护缓存以及批处理等 。执行器在的角色更像是一个管理员,接收SQL请求,然后根据缓存、批处理等逻辑来决定如何执行这个SQL请求,并交给JDBC处理器执行具体SQL
  • JDBC处理器: 主要具体处理JDBCSQL和参数 。在会话中每调用一次CRUD,JDBC处理器就会生成一个实例与之对应(命中缓存除外)
代码语言:javascript复制
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);

请注意在一次SQL会话过程当中四个组件的实例比值分别是 1:1:1:n


组件之间的关系

一个SQL请求通过会话到达执行器,然后交给对应的JDBC处理器进行处理。

另外所有的组件都不是线程安全的,不能跨线程使用 (currentSql 全局变量 ,线程不安全 )

接下来我们重点看下Executor组件,从源码上剖析该组件的设计思想。


Executor 执行器组件

架构总览

Executor是MyBatis执行者接口 ,执行器的主要功能包括:

  • 基本功能:改、查,(增删—>也是改)
  • 缓存维护:这里的缓存主要是为一级缓存服务,功能包括创建缓存Key、清理缓存、判断缓存是否存在
  • 事务管理:提交、回滚、关闭、批处理刷新

接口继承关系

后面我们重点看下Executor的 三个实现子类。

分别是:SimpleExecutor(简单执行器)、ReuseExecutor(重用执行器)、BatchExecutor(批处理执行器)。

MyBatis源码-深入解读Executor的三个实现类


0 人点赞