0%

MyBatis TypeHandler 深度解析:Java 与 JDBC 类型转换的桥梁(从原理到自定义实践)

在 MyBatis 与数据库交互过程中,Java 类型与 JDBC 类型无法直接兼容(如 Java 的 Date 与 JDBC 的 Timestamp、Java 枚举与 JDBC 的 VARCHAR)。TypeHandler(类型处理器)正是解决这一问题的核心组件,负责参数绑定时的 Java→JDBC 类型转换结果映射时的 JDBC→Java 类型转换,是 MyBatis 数据交互的 “翻译官”。从 “接口定义→核心实现→注册管理→自定义实践” 四个维度,彻底拆解 TypeHandler 的工作机制。

TypeHandler 核心定位与接口规范

TypeHandler 是 MyBatis 中类型转换的标准接口,定义了 “参数绑定” 和 “结果获取” 两类核心操作,覆盖所有数据交互场景。

TypeHandler 接口定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public interface TypeHandler<T> {
// ------------------------------ 1. 参数绑定:Java类型 → JDBC类型 ------------------------------
// 为 PreparedStatement 绑定参数时调用,将 Java 对象转为 JDBC 支持的类型
// 参数:ps=PreparedStatement 对象;i=参数索引(从1开始);parameter=Java 参数值;jdbcType=目标 JDBC 类型
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;

// ------------------------------ 2. 结果获取:JDBC类型 → Java类型 ------------------------------
// 从 ResultSet 按列名获取值,转为 Java 类型
T getResult(ResultSet rs, String columnName) throws SQLException;

// 从 ResultSet 按列索引获取值,转为 Java 类型
T getResult(ResultSet rs, int columnIndex) throws SQLException;

// 从 CallableStatement(存储过程)按列索引获取值,转为 Java 类型
T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}
接口设计思路:
  • 泛型 <T>:指定该 TypeHandler 处理的 Java 类型(如 DateTypeHandler 的泛型是 Date);
  • 两类操作:
    • setParameter:参数绑定时的 “正向转换”(Java→JDBC),由 ParameterHandler 调用;
    • getResult:结果映射时的 “反向转换”(JDBC→Java),由 ResultSetHandler 调用。

BaseTypeHandler:简化自定义实现的抽象基类

MyBatis 提供 BaseTypeHandler<T> 抽象类,它实现了 TypeHandler<T> 接口,并抽离了 null 值的统一处理逻辑,让自定义 TypeHandler 只需关注 “非 null 类型转换”,大幅降低开发成本。

核心源码解析
阅读全文 »

MyBatis Mapper 接口与 SQL 绑定机制全解析:从动态代理到 SQL 执行

MyBatis 的核心特性之一是 “接口无实现类却能执行 SQL”—— 开发者只需定义 Mapper 接口(如 UserMapper),并在 XML / 注解中编写对应 SQL,调用接口方法即可触发 SQL 执行。这一 “魔法” 的本质是 JDK 动态代理 + 注册中心 + 方法与 SQL 绑定 的协同机制。从 “注册→代理→绑定→执行” 四个阶段,彻底拆解 Mapper 接口与 SQL 的绑定原理。

核心问题:为什么接口能执行 SQL?

Mapper 接口本身没有实现类,MyBatis 通过以下机制实现 “接口调用→SQL 执行” 的闭环:

  1. 注册中心(MapperRegistry):初始化时扫描 Mapper 接口,将 “接口” 与 “代理工厂(MapperProxyFactory)” 绑定并注册;
  2. 动态代理(MapperProxy):调用接口方法时,通过代理工厂生成接口的动态代理对象,拦截方法调用;
  3. 方法与 SQL 绑定(MapperMethod):代理对象将接口方法解析为 “SQL 标识(namespace+methodName)” 和 “参数信息”,找到对应的 SQL;
  4. 委托执行(SqlSession):通过 SqlSession 调用底层执行器(Executor),最终执行 SQL 并返回结果。

阶段 1:初始化注册 ——MapperRegistry 管理绑定关系

MapperRegistry 是 MyBatis 的 Mapper 接口注册中心,负责在 MyBatis 初始化时,将 Mapper 接口与对应的 “代理工厂(MapperProxyFactory)” 关联并存储,为后续生成代理对象做准备。

1. 核心属性:存储接口与代理工厂的映射

阅读全文 »

MyBatis ParameterHandler:参数绑定的核心桥梁(从源码到实践)

ParameterHandler 是 MyBatis 中连接 Java 参数与 JDBC 预编译 SQL 的关键组件,负责将 Java 中的参数值正确绑定到 SQL 语句的占位符(?)上。它通过协调 TypeHandler 完成 Java 类型到 JDBC 类型的转换,是 SQL 预编译后执行前的最后一步关键操作。本文结合源码,深入解析 ParameterHandler 的工作机制、参数绑定流程及核心设计。

ParameterHandler 接口:参数处理的规范定义

ParameterHandler 接口仅定义了两个核心方法,清晰界定了参数处理的职责边界:

1
2
3
4
5
6
7
public interface ParameterHandler {
// 1. 获取原始参数对象(如 JavaBean、Map、基本类型等)
Object getParameterObject();

// 2. 核心方法:将参数绑定到 PreparedStatement 的占位符上
void setParameters(PreparedStatement ps) throws SQLException;
}
  • getParameterObject():提供对原始参数的访问,方便其他组件(如插件)获取参数信息;
  • setParameters(PreparedStatement):负责将 Java 参数值通过 JDBC API(如 ps.setInt(1, value))绑定到 SQL 占位符,是参数处理的核心逻辑。

DefaultParameterHandler:唯一实现类的核心逻辑

MyBatis 仅提供了一个 ParameterHandler 实现类 ——DefaultParameterHandler,它完整实现了从 Java 参数到 JDBC 占位符的绑定流程。其核心依赖包括:

阅读全文 »

MyBatis StatementHandler 深度解析:数据库交互的核心执行者

StatementHandler 是 MyBatis 中直接与数据库交互的核心接口,负责管理 JDBC 的 Statement 对象(Statement/PreparedStatement/CallableStatement),协调 ParameterHandler(参数设置)和 ResultSetHandler(结果映射),完成 “SQL 预编译→参数绑定→SQL 执行→结果处理” 的全流程。从 “接口定位→架构设计→核心实现→调用链路” 四个维度,彻底拆解 StatementHandler 的工作机制,并揭示其背后的设计模式。

StatementHandler 核心定位与接口规范

核心职责

StatementHandler 是 MyBatis 与数据库交互的 “最后一公里”,核心职责可概括为 5 点:

  1. 创建 Statement 对象:根据 SQL 类型(无参数 / 预编译 / 存储过程)创建对应的 JDBC Statement
  2. SQL 预编译:对预编译 SQL(PreparedStatement)进行编译,提升执行效率;
  3. 参数绑定:委托 ParameterHandler 为 SQL 占位符(?)设置参数;
  4. SQL 执行:执行 select/insert/update/delete 及批量操作;
  5. 结果转发:将执行结果(ResultSet)委托 ResultSetHandler 映射为 Java 对象。

接口定义:核心方法规范

StatementHandler 接口定义了数据库交互的标准方法,所有实现类需遵循该规范:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public interface StatementHandler {
// 1. 从数据库连接中创建 Statement 对象(预编译 SQL 在此步骤)
Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException;

// 2. 为 Statement 绑定参数(仅 PreparedStatement/CallableStatement 需实现)
void parameterize(Statement statement) throws SQLException;

// 3. 批量执行 SQL(添加 SQL 到批量队列)
void batch(Statement statement) throws SQLException;

// 4. 执行 update/insert/delete,返回受影响行数
int update(Statement statement) throws SQLException;

// 5. 执行 select,返回结果列表(委托 ResultSetHandler 处理)
<E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException;

// 6. 执行 select,返回游标(流式读取大数据量)
<E> Cursor<E> queryCursor(Statement statement) throws SQLException;

// 7. 获取当前 SQL 对应的 BoundSql(封装 SQL 语句、参数映射等)
BoundSql getBoundSql();

// 8. 获取当前 StatementHandler 关联的 ParameterHandler
ParameterHandler getParameterHandler();
}

架构设计:接口 + 抽象基类 + 具体实现(模板方法 + 策略模式)

MyBatis 对 StatementHandler 的实现采用 “接口定义规范 + 抽象基类封装通用逻辑 + 具体类实现差异化功能” 的架构,并通过 模板方法模式(抽象基类)和 策略模式(路由类)降低耦合,提升扩展性。

架构层级图

阅读全文 »

MyBatis 执行器(Executor)深度解析:从架构到实战

Executor 是 MyBatis 的核心执行引擎,负责数据库操作的调度、缓存管理与事务控制,是 SqlSession 方法的实际执行者。MyBatis 通过 ExecutorType 提供三种基础执行器(SimpleExecutor/ReuseExecutor/BatchExecutor),并通过 CachingExecutor 实现二级缓存,形成 “基础执行 + 缓存增强” 的装饰器架构。从 “架构设计→核心实现→缓存机制→实战选型” 四个维度,彻底拆解 Executor 的工作原理。

Executor 核心定位与架构

核心职责

Executor 是 MyBatis 与数据库交互的 “总指挥”,核心职责包括:

  • 调度 StatementHandler/ParameterHandler/ResultSetHandler 完成 SQL 执行;
  • 管理一级缓存(会话级)和二级缓存(应用级);
  • 控制事务提交 / 回滚,处理批量 SQL 执行;
  • 生成缓存键(CacheKey),实现缓存命中逻辑。

架构设计:接口 + 抽象基类 + 具体实现

MyBatis 采用 “接口定义规范 + 抽象类封装通用逻辑 + 具体类实现差异化功能” 的设计,同时通过装饰器模式CachingExecutor)增强缓存能力:

graph TD
    A[Executor 接口] --> B[BaseExecutor 抽象类]
    B --> C[SimpleExecutor 简易执行器]
    B --> D[ReuseExecutor 复用执行器]
    B --> E[BatchExecutor 批量执行器]
    A --> F[CachingExecutor 缓存执行器 装饰器]
    F --> B[包装 BaseExecutor 子类]
  • 接口(Executor):定义数据库操作的核心方法(update/query/commit/rollback 等);
  • 抽象基类(BaseExecutor):实现通用逻辑(一级缓存、事务管理、延迟加载),暴露 doUpdate/doQuery 等抽象方法由子类实现;
  • 具体执行器:实现差异化 SQL 执行逻辑(如 Statement 复用、批量处理);
  • 装饰器(CachingExecutor):包装基础执行器,添加二级缓存功能,不改变原有执行逻辑。

ExecutorType 枚举:执行器类型

MyBatis 通过 ExecutorType 枚举指定执行器类型,决定 SQL 执行策略:

ExecutorType 对应执行器 核心特点 适用场景
SIMPLE SimpleExecutor 每次执行 SQL 新建 Statement,执行后关闭 大多数单条 SQL 场景(默认类型)
REUSE ReuseExecutor 按 SQL 缓存 Statement,复用避免重建 重复执行相同 SQL(如循环查询)
BATCH BatchExecutor 缓存多条 SQL,批量提交 批量插入 / 更新 / 删除(减少网络开销)

Executor 的创建流程

Executor 通过 Configuration.newExecutor() 方法创建,核心逻辑是 “根据 ExecutorType 生成基础执行器,若开启二级缓存则用 CachingExecutor 包装”:

1. 核心源码:Configuration.newExecutor ()

阅读全文 »