mybatis 源码刨析扩展之 动态SQL

本文探讨了MyBatis动态SQL的执行原理,通过OGNL计算表达式值来动态拼接SQL。详细剖析了SqlNode接口、SqlSource、BoundSql类以及BaseBuilder接口的实现类,如XMLConfigBuilder、XMLMapperBuilder、XMLStatementBuilder和XMLScriptBuilder在动态SQL中的作用。重点分析了XMLMapperBuilder的parse方法、XMLStatementBuilder的解析过程以及XMLLanguageDriver如何创建SqlSource。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、执行原理

使用 OGNL 从 sql 参数对象中计算表达式的值,根据表达式的值动态拼接 sql,以此来完成动态 sql 的功能。

二、主要类源码

MyBatis 中一些关于动态 SQL 的接口和类。

1、SqlNode 接口

简单理解就是 xml 中的每个标签,比如 sql 的 update、if 标签:

public interface SqlNode {
   
    boolean apply(DynamicContext context);
}

2、SqlSource

Sql 源接口,代表从 xml 文件或注解映射的 sql 内容,主要就是用于创建 BoundSql,有实现类 DynamicSqlSource(动态 Sql 源),StaticSqlSource(静态 Sql 源)等:

public interface SqlSource {
   
    BoundSql getBoundSql(Object parameterObject);
}

3、BoundSql 类

封装 mybatis 最终产生 sql 的类,包括 sql 语句,参数,参数源数据等参数:

public class BoundSql {
   

  private final String sql;
  private final List<ParameterMapping> parameterMappings;
  private final Object parameterObject;
  private final Map<String, Object> additionalParameters;
  private final MetaObject metaParameters;
}

4、BaseBuilder 接口及其实现类

继承图

这些 Builder 的作用就是用于构造 sql。
分析下其中4个 Builder:

1)XMLConfigBuilder

解析 mybatis 中 configLocation 属性中的全局 xml 文件,内部会使用 XMLMapperBuilder 解析各个 xml 文件。

2)XMLMapperBuilder

遍历 mybatis 中 mapperLocations 属性中的 xml 文件中每个节点的 Builder,比如 user.xml,内部会使用 XMLStatementBuilder 处理 xml 中的每个节点。

3)XMLStatementBuilder

解析 xml 文件中各个节点,比如 select、insert、update、delete 节点,内部会使用 XMLScriptBuilder 处理节点的 sql 部分,遍历产生的数据会丢到 Configuration 的 mappedStatements 中。

4)XMLScriptBuilder

解析 xml 中各个节点 sql 部分的 Builder。
LanguageDriver 接口及其实现类,该接口主要的作用就是构造 sql。

三、源码刨析

1、 XMLMapperBuilder 中的 parse 方法:

public void parse() {
   
    // 判断当前 Mapper 是否已经加载过
    if (!configuration.isResourceLoaded(resource)) {
   
        // 解析 '<mapper />' 节点,根据 Xpath 解析 mapper 节点
        configurationElement(parser.evalNode("/mapper"));
        // 标记该 Mapper 已经加载过
        configuration.addLoadedResource(resource);
        // 绑定 Mapper
        bindMapperForNamespace();
    }

    // 解析待定的 <resultMap /> 节点
    parsePendingResultMaps();
    // 解析待定的 <cache-ref /> 节点
    parsePendingCacheRefs();
    // 解析待定的 SQL 语句的节点
    parsePendingStatements();
}

// 解析 mapper 节点,根据 Xpath 解析 mapper 节点
private void configurationElement(XNode context) {
   
    try {
    
        // 获取 mapper 节点的 namespace 属性,如 com.lagou.mapper.UserMapper
        String namespace = context.getStringAttribute(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jason559

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值