一、前言

StatementHandler 封装了底层 JDBC 的 Statement

二、体系结构

StatementHandler.png

  • StatementHandler: 底层接口,定义查询、更新、参数化等接口。
  • RoutingStatementHandler: 有点类似工厂类,根据不同的 statementType 实例化相应的 StatementHandler,并在内部持有该对象的引用。
  • BaseStatementHandler: 抽象类,实现 StatementHandler 接口。
  • SimpleStatementHandler: 对应 JDBC 的 Statement
  • PreparedStatementHandler: 对应 JDBC 的 PreparedStatement
  • CallableStatementHandler: 对应 JDBC 的 CallableStatementHandler

    2.1 BaseStatementHandler

    BaseStatementHandler 为抽象类,实现 StatementHandler 接口。它拥有子类所需的全部变量。主要有:

  • TypeHandlerRegistry: 类型处理器。

  • ResultSetHandler: 结果集处理器。
  • ParameterHandler: 参数处理器。
  • Executor: 执行器

可以简单把它想象为封装了以上对象的抽象类而已,主要实现了 org.apache.ibatis.executor.statement.StatementHandler#prepare()方法,但其中的 instantiateStatement() 还是交给子类完成,并且在构造器当中如果获取主要生成器,调用主要生成器的 processBefore 方法进行主键获取。比如 Oracel 就需要这种方式获取主键。
BaseStatementHandler.png

2.2 SimpleStatementHandler

SimpleStatementHandler 是 Mybatis 最简单的 Handler,看一下 query() 接口:
SimpleStatementHandler#query.png
和我们使用 JDBC 编程一样,调用 statement.execute(sql); 方法调用 JDBC 驱动就能获取数据库数据了。后续使用 ResultSetHandler 进行数据到对象/集合等类型的转换操作。这我们后续详解。
当然,Mybatis 默认的不是使用这个 Handler 处理 SQL 查询,而是使用 PreparedStatementHandler,因为它存在预编译,所以执行效率更高。

2.3 PreparedStatementHandler

2.3.1 query()

PreparedStatementHandler#query.png
PreparedStatementHandler 与 JDBC 的 PreparedStatement,因为它存在预编译,所以相对 Statement 来说执行效率更高,但是他也有局限性,每次只能编译相同的 SQL 语句(参数可以不同)。
从上面代码来看,PreparedStatementHandler 执行更简单,直接调用 ps.execute() 即可。后续从 PreparedS 对象中获取结果集并转换相应的类型。

2.3.1 update()

下面我们了解一下 PreparedStatementHandlerupdate() 执行流程:
PreparedStatementHandler#update.png
逻辑非常简单,主要是增加了主键的回调设置,比如我们 insert 一条语句需要获取对应的主键 ID 做后续业务的关联,这里,就是 Mybatis 帮我们回写对应的 Object 字段里。

四、生命周期

4.1 创建

每次 Executor 相关方法执行时就会新建 StatementHandler 对象,当前,这个 StatementHandler 并非抽象类 BaseStatementHandler 的子类,而是 RoutingStatementHandler,使用代理模式 / 工厂模式 ?。在构造器时根据参数 MappedStatement#statementType 实例化不同的类型的 StatementHandler 对象。存在如下对应关系:

  • STATEMENT: SimpleStatementHandler
  • PREPARED: PreparedStatementHandler
  • CALL: CallableStatementHandler

RoutingStatementHandler#constructor.png

五、总结

以上源码并非面面具到,只贴出核心的、部分的源码给大家参考和理解,有些地方不必深究,我们只是对 Mybatis 的设计思想、部分实现细节(比如如何做 update、query) 等有一定的了解,并非逐字逐行看。

总体来说,StatementHandler 接口是 Mybatis 框架离 JDBC 原生调用实现最近的一层,它抽象了 Mybatis 底层才会使用到的接口,并非给用户直接调用的。

BaseStatementHandler 持有多个处理器对象,包含结果集处理器、参数处理器等,它们是 一条 SQL 完成执行不可缺少的一部分,每个类职责单一,便于维护和扩展。