小菜鸟

java菜鸟号正在起航

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 接口仅定义了两个核心方法,清晰界定了参数处理的职责边界:

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 接口定义了数据库交互的标准方法,所有实现类需遵循该规范:

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 ()

阅读全文 »

ThreadLocal线程本地存储详解

在并发编程中,处理共享数据时通常需要同步机制(如synchronizedLock)来保证线程安全。但 ThreadLocal 提供了另一种思路:让共享数据不再共享,通过为每个线程创建独立的变量副本,实现线程间的数据隔离。

ThreadLocal 核心原理

基本概念

ThreadLocal(线程本地变量)为每个线程维护一个独立的变量副本,线程对副本的修改不会影响其他线程。其核心思想是:

  • 空间换时间:通过为每个线程分配独立内存空间,避免线程间的同步开销。
  • 数据隔离:每个线程操作自己的副本,消除竞争条件。

实现结构

ThreadLocal 的实现依赖于Thread类和ThreadLocalMap

  • Thread 类:每个线程持有两个ThreadLocalMap对象:

    ThreadLocal.ThreadLocalMap threadLocals = null;       // 线程本地变量
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;  // 可继承的本地变量
  • ThreadLocalMap:ThreadLocal 的静态内部类,本质是一个哈希表,key 为 ThreadLocal 对象,value 为线程的变量副本

ThreadLocal 核心方法

ThreadLocal 通过以下方法操作线程的变量副本:

get():获取当前线程的变量副本

阅读全文 »
0%