MyBatis四大组件Executor、StatementHandler、ParameterHandler、ResultSetHandler 详解(1)

简介: MyBatis四大组件Executor、StatementHandler、ParameterHandler、ResultSetHandler 详解

前言

上次我们在说mybatis 的 plugin 功能的时候,提到了其可作用于myBatis 的四大组件,也放了一个基础的模型图,但是对于这四大组件更具体的功能和原理:却没有进一步说明,今天就来完成这项工作


一、四大组件的用途

先来看一张图mybatis的类引用图,然后我们再详细解释


4d15a350ba0d48b5b8770cbd167a2fde.png

二、Executor

1. Executor接口方法

我们现浏览下Executor 接口都提供了什么方法:


public interface Executor {
  ResultHandler NO_RESULT_HANDLER = null;
  int update(MappedStatement ms, Object parameter) throws SQLException;
  <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler,
      CacheKey cacheKey, BoundSql boundSql) throws SQLException;
  <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler)
      throws SQLException;
  <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;
  List<BatchResult> flushStatements() throws SQLException;
  void commit(boolean required) throws SQLException;
  void rollback(boolean required) throws SQLException;
  CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);
  boolean isCached(MappedStatement ms, CacheKey key);
  void clearLocalCache();
  void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);
  Transaction getTransaction();
  void close(boolean forceRollback);
  boolean isClosed();
  void setExecutorWrapper(Executor executor);
}

我们知道,执行器是直接存在会话中的,在整个调用链路中还是比较偏上层的,可以看到其主要的功能就是三点:


1.数据的查改

2.事务的提交与回滚

3.还有mybatis本身缓存的处理

2. 功能说明

我们把该接口的几个默认实现都列出来,慢慢来介绍。


aaf1019897c74e56aca33d13361be8fa.png

1.CachingExecutor: 独树一帜,它本身并不具备其他执行器的功能,不能直接进行sql操作,也无没获取连接,自然也无法执行事务提交或回滚,它只是个缓存容器(二级缓存),所以每一次使用CachingExecutor时,其内必须含一个其他执行器,sql和事务的操作,其实都由该其他执行器负责。

2.BaseExecutor: 一个抽象类,执行器的基本实现。该类主要完成了一些事务管理和一级缓存准备的工作,而查询和更新的核心逻辑则是空方法,所以不直接使用,一般使用的都是其三个子类,其子类将重写核心方法。

3.SimpleExecutor:Mybatis默认的执行器,它对每个SQL语句都创建一个Statement对象,执行完毕后立即关闭。SimpleExecutor适用于执行一些短期查询、插入、更新或删除等SQL操作,但频繁的创建和关闭Statement对象会导致较差的性能。

4.ReuseExecutor:重用已经创建的Statement对象,将相同sql的多次查询或更新操作放到同一个Statement中执行,提高了性能。

5.BatchExecutor:用于批量执行SQL语句,它将多个SQL语句放到同一个Statement中执行,从而减少了与数据库的通信次数

我们以一个查询语句来看看执行器到底在干什么

  public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
      // 获取总配置
      Configuration configuration = ms.getConfiguration();
      // 创建个 StatementHandler ,注意此处可应用自定义plugin来修改默认Handler的逻辑
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      // 使用 StatementHandler 生成Statement ,该对象是sql语句的封装,将交由jdbc来执行
      // 注意,默认的几种 handler 创建Statement 的逻辑都是一样的
      stmt = prepareStatement(handler, ms.getStatementLog());
      // 使用 某种handler 来执行sql,不同handler 稍有不同
      return handler.query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

可以看出,Executor执行器的核心功能,就是新建出一个statementHandler , 然后利用该handler创建一个statement 的实例。最后调用该实例的对应方法完成sql的执行。其基础和默认实现类是SimpleExecutor,另两种执行器则是该基础执行器在特殊场景下的优化版本。


而CachingExecutor则只专注二级缓存,没有上述核心功能,所以无法单独出现,其必定引用着一个“正常”的执行器,以便二级缓存没结果时,能正常查询数据库。


97a13a43592c4c948c0ee159b748c11d.png


三、StatementHandler

上面,我们讲执行器的时候,已经提到了 StatementHandler,现在则详细讲讲,在讲之前,还是得介绍下什么是Statement?


1. Statement介绍

Statement 是Java JDBC API中定义的一个接口,位于java.sql 包下,是一种执行静态SQL语句的对象,可以用于执行SQL语句的查询、更新、插入和删除等操作。我们可以看其上的官方注释:


The object used for executing a static SQL statement and returning the results it produces.

By default, only one ResultSet object per Statement object can be open at the same time. Therefore, if the reading of one ResultSet object is interleaved with the reading of another, each must have been generated by different Statement objects. All execution methods in the Statement interface implicitly close a current ResultSet object of the statement if an open one exists.

用于执行静态SQL语句并返回其生成的结果的对象。

默认情况下,每个Statement对象只能同时打开一个ResultSet对象。因此,如果一个ResultSet对象的读取与另一个ResultSet对象的读取交错进行,则每个ResultSet对象必须由不同的Statement对象生成。如果存在打开的语句的ResultSet对象,则Statement接口中的所有执行方法都隐式关闭该语句的当前ResultSet对象。


换句话说,该对象就是 jdbc 的核心, 负责在已经建立数据库连接的基础上,向数据库发送要执行的SQL语句。


2. StatementHandler 接口方法

StatementHandler 是 mybatis 内的一个接口,从名字看,它主要是围绕statement进行管理和操作的,照例,我们先看看它定义的所有方法

public interface StatementHandler {
  Statement prepare(Connection connection, Integer transactionTimeout)
      throws SQLException;
  void parameterize(Statement statement)
      throws SQLException;
  void batch(Statement statement)
      throws SQLException;
  int update(Statement statement)
      throws SQLException;
  <E> List<E> query(Statement statement, ResultHandler resultHandler)
      throws SQLException;
  <E> Cursor<E> queryCursor(Statement statement)
      throws SQLException;
  BoundSql getBoundSql();
  ParameterHandler getParameterHandler();
}


从这些方法来看,StatementHandler 的主要功能应该包括


1.创建statement,并为其绑定参数

2.通过statement,对数据库执行sql,并对结果集进行映射

3. 不同实现类的区别

既然是接口,我们先看看mybatis 为其提供了几种实现类

754a15406d2f4f83b371109f36afc581.png

可以看到,其几乎好执行器接口的结构相同,下面,我们来说说这些实现类的区别


1.RoutingStatementHandler: 路由,不带有任何实际逻辑,但是会根据报表statemnet的类型创建一个实现类,然后作为真实的报表处理器。

2.BaseStatementHandler: 一个抽象类,报表处理器的基本实现。该类存储着一些变量,如参数处理器和结果处理器。且实现了创建报表的方法,但不含sql执行的具体操作。

3.PreparedStatementHandler:用于执行预编译的SQL语句,并支持参数绑定和批量操作。

4.CallableStatementHandler:用于执行存储过程和函数等数据库特殊语法,支持输入、输出和输入输出参数的绑定。

5.SimpleStatementHandler:用于执行简单的SQL语句,不支持参数绑定和批量操作

毫无疑问,在实际应用中,我们的sql大多是带参数的,即含有#{},所以一般会被路由创建个PreparedStatementHandler,而静态sql 和只是用 ${} 的sql 则使用的是 SimpleStatementHandler

我们通过PreparedStatementHandler 里的查询方法来看其功能

  @Override
  public void parameterize(Statement statement) throws SQLException {
    // 把参数装填进报表
    parameterHandler.setParameters((PreparedStatement) statement);
  }
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    // 将报表类型向上转型为 PreparedStatement 
    PreparedStatement ps = (PreparedStatement) statement;
    // 报表执行sql
    ps.execute();
    // 使用结果处理器,处理返回值
    return resultSetHandler.handleResultSets(ps);
  }

可以看出,StatementHandler 的功能还是直接操作statement,并围绕sql的准备,执行,返回值处理三个点来运行的,


目录
相关文章
|
7月前
|
存储 前端开发 Java
MyBatis 四大核心组件之 ResultSetHandler 源码解析
MyBatis 四大核心组件之 ResultSetHandler 源码解析
|
7月前
|
SQL 前端开发 Java
MyBatis 四大核心组件之 ParameterHandler 源码解析
MyBatis 四大核心组件之 ParameterHandler 源码解析
|
7月前
|
SQL 前端开发 Java
MyBatis 四大核心组件之 StatementHandler 源码解析
MyBatis 四大核心组件之 StatementHandler 源码解析
|
SQL Java 数据库连接
MyBatis的基本概念和核心组件
MyBatis的基本概念和核心组件
|
安全 Java 数据库连接
Rpamis-security-基于Mybatis-Plugin的一站式加解密脱敏安全组件
项目是一个基于Mybatis插件开发的安全组件,旨在提供更优于市面上组件的脱敏、加解密落库等企业数据安全解决方案。组件提供注解式编程方式,开发者只需要对需要处理的字段或方法加上对应注解,无需关心安全相关需求,由组件全自动完成脱敏、加解密等功能
191 7
|
7月前
|
SQL 缓存 Java
MyBatis 四大核心组件之 Executor 源码解析
MyBatis 四大核心组件之 Executor 源码解析
|
2月前
|
Java 数据库连接 Maven
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和MyBatis Generator,使用逆向工程来自动生成Java代码,包括实体类、Mapper文件和Example文件,以提高开发效率。
150 2
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
|
2月前
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
79 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
|
2月前
|
前端开发 Java Apache
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
本文详细讲解了如何整合Apache Shiro与Spring Boot项目,包括数据库准备、项目配置、实体类、Mapper、Service、Controller的创建和配置,以及Shiro的配置和使用。
556 1
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
|
2月前
|
SQL Java 数据库连接
mybatis使用二:springboot 整合 mybatis,创建开发环境
这篇文章介绍了如何在SpringBoot项目中整合Mybatis和MybatisGenerator,包括添加依赖、配置数据源、修改启动主类、编写Java代码,以及使用Postman进行接口测试。
27 0
mybatis使用二:springboot 整合 mybatis,创建开发环境