MyBatis XMLMapperBuilder 是如何将 SQL 语句解析成可执行的对象? 如何将结果映射规则解析成对应的处理器?

1. XMLMapperBuilder 如何将 SQL 语句解析成可执行对象 (MappedStatement):

XMLMapperBuilder 解析 <select>, <insert>, <update>, <delete> 等 SQL 语句元素时,并不仅仅是简单地读取 SQL 文本,而是要将 SQL 语句和相关的配置信息 封装成 MappedStatement 对象MappedStatement 对象才是 MyBatis 运行时真正可执行的 SQL 对象。 这个过程主要涉及以下几个关键步骤:

  • 1.1. 解析 SQL 语句文本 (SqlSource):

    XMLMapperBuilder 会读取 <select>, <insert>, <update>, <delete> 元素体内的 SQL 语句文本。 SQL 语句文本可能包含:

    • 静态 SQL: 普通的 SQL 语句,不包含任何动态 SQL 标签或占位符。
    • 动态 SQL: 包含 MyBatis 的动态 SQL 标签 (例如 <if>, <choose>, <foreach>, <where>, <set>, <trim>, ${}, #{} 等)。
    • 参数占位符: #{}${} 占位符,用于在运行时动态地替换参数值。

    XMLMapperBuilder 会根据 SQL 语句文本的类型,创建不同的 SqlSource 对象来表示 SQL 语句的来源和处理方式。 SqlSource 接口是 MyBatis 中表示 SQL 语句来源的抽象接口,它有以下几种实现类:

    • RawSqlSource: 用于表示 静态 SQL。 对于静态 SQL,SQL 语句文本在解析时就已经确定,运行时无需动态构建。
    • DynamicSqlSource: 用于表示 动态 SQL。 对于动态 SQL,SQL 语句文本在运行时需要根据参数值进行动态构建。 DynamicSqlSource 会负责解析和处理动态 SQL 标签,并生成最终的可执行 SQL 语句。
    • ProviderSqlSource: 用于表示 基于 Provider 类的 SQL。 SQL 语句不是直接写在 XML 文件中,而是通过一个 Java Provider 类动态生成。

    XMLMapperBuilder 会根据 SQL 语句是否包含动态 SQL 标签来判断创建 RawSqlSource 还是 DynamicSqlSource。 如果 SQL 语句中使用了动态 SQL 标签,则创建 DynamicSqlSource,否则创建 RawSqlSource。 如果是基于 Provider 类的 SQL,则创建 ProviderSqlSource

    示例代码 (简化版,展示 XMLMapperBuilder 如何创建 SqlSource):

    // 假设 XMLMapperBuilder 解析 <select id="getUserById"> 元素
    XNode selectNode = ...; // 代表 <select> 元素的 XNode 对象
    String sqlText = selectNode.getStringBody(); // 获取 <select> 元素体内的 SQL 语句文本SqlSource sqlSource;
    if (sqlTextContainsDynamicSqlTags(sqlText)) { // 检查 SQL 文本是否包含动态 SQL 标签 (简化判断逻辑)sqlSource = new DynamicSqlSource(configuration, selectNode); // 创建 DynamicSqlSource
    } else {sqlSource = new RawSqlSource(configuration, selectText); // 创建 RawSqlSource
    }
    
  • 1.2. 解析参数映射 (ParameterMap 和 内联参数映射):

    XMLMapperBuilder 会解析 SQL 语句中的参数映射配置。 MyBatis 支持两种参数映射方式:

    • parameterMap 属性 (已过时,不推荐使用): 通过 <select>, <insert>, <update>, <delete> 元素的 parameterMap 属性引用外部定义的 <parameterMap> 元素。 XMLMapperBuilder 会解析 <parameterMap> 元素及其子元素 <parameter>,构建 ParameterMap 对象,并将其关联到 MappedStatementparameterMap 方式已经过时,不推荐使用。
    • 内联参数映射 (#{}${}): 在 SQL 语句文本中直接使用 #{}${} 占位符进行参数映射。 这是 现代 MyBatis 开发中推荐使用的参数映射方式XMLMapperBuilder 会解析 SQL 语句文本中的 #{}${} 占位符,并提取占位符中的参数属性名、jdbcType、typeHandler 等信息。

    XMLMapperBuilder 会将解析得到的参数映射信息 存储到 MappedStatement 对象中,以便在运行时进行参数绑定。

  • 1.3. 解析结果映射 (ResultMap 和 resultType):

    XMLMapperBuilder 会解析 <select> 元素的结果映射配置,用于将查询结果集映射到 Java 对象。 MyBatis 支持两种结果映射方式:

    • resultMap 属性: 通过 <select> 元素的 resultMap 属性引用外部定义的 <resultMap> 元素。 XMLMapperBuilder 会解析 <resultMap> 元素及其子元素 (<id>, <result>, <association>, <collection>, <discriminator>), 构建 ResultMap 对象,并将其关联到 MappedStatementresultMap 方式适用于复杂的结果集映射场景 (例如关联查询、集合属性、多态映射等)。
    • resultType 属性: 通过 <select> 元素的 resultType 属性直接指定结果类型。 resultType 方式适用于简单的结果集映射场景 (例如单表查询,结果类型是基本类型或 POJO)。 MyBatis 会自动进行简单的属性映射。

    XMLMapperBuilder 会根据 <select> 元素配置的 resultMapresultType 属性, 创建 ResultMap 对象 (如果使用 resultMap) 或记录 resultType,并将结果映射信息存储到 MappedStatement 对象中,以便在运行时进行结果集映射。

  • 1.4. 构建 MappedStatement 对象:

    XMLMapperBuilder 在完成 SQL 语句文本 (SqlSource)、参数映射和结果映射的解析后,会将这些信息,以及 <select>, <insert>, <update>, <delete> 元素上的其他属性 (例如 statementType, timeout, fetchSize, cache 等), 整合到一个 MappedStatement 对象中

    MappedStatement 对象包含了执行一个 SQL 操作所需的所有信息,是 MyBatis 运行时执行 SQL 的核心对象。

  • 1.5. 注册 MappedStatementConfiguration:

    XMLMapperBuilder 会将构建好的 MappedStatement 对象 注册到 Configuration 对象的 mappedStatements 属性 (一个 StrictMap<MappedStatement>) 中。 注册时,会使用 Mapper 接口的全限定名 + SQL 语句的 id 属性作为 MappedStatement 的唯一 ID (mappedStatementId)。

2. XMLMapperBuilder 如何将结果映射规则解析成对应的处理器 (ResultMap 和 ResultHandler):

XMLMapperBuilder 在解析 <resultMap> 元素时,会构建 ResultMap 对象。 ResultMap 对象本身 不是处理器 (Handler),而是 结果映射规则的定义。 它描述了如何将查询结果集中的列映射到 Java 对象的属性。

真正的结果集映射处理器是 ResultHandler 接口的实现类。 ResultHandler 接口负责 逐行处理查询结果集,并将每一行数据按照 ResultMapresultType 定义的映射规则,映射到 Java 对象。

XMLMapperBuilder 在解析结果映射规则时,主要完成以下工作,为后续的结果集映射处理做准备:

  • 2.1. 构建 ResultMap 对象 (如果定义了 <resultMap>):

    XMLMapperBuilder 解析 <resultMap> 元素时,会根据 <resultMap> 元素的配置信息 (包括 id, type, extends, autoMapping, <constructor>, <id>, <result>, <association>, <collection>, <discriminator>), 构建一个 ResultMap 对象ResultMap 对象会存储结果映射的所有规则,例如:

    • id: resultMap 的唯一 ID。
    • type: 结果映射的目标 Java 类型。
    • resultMappings: 一个 List<ResultMapping>, 存储了所有的属性映射规则 (<id>, <result>, <association>, <collection>, <discriminator> 对应的 ResultMapping 对象)。
    • constructorResultMappings, idResultMappings, propertyResultMappings, associationResultMappings, collectionResultMappings, discriminatorResultMappings: 不同类型的 ResultMapping 列表,方便按类型查找。
    • autoMapping: 是否开启自动映射。
    • extendsResultMap: 继承的 ResultMap 的 ID。
    • discriminator: 鉴别器 (Discriminator)。

    ResultMap 对象本身并不执行映射操作,它只是结果映射规则的描述。

  • 2.2. 将 ResultMap 对象注册到 Configuration:

    XMLMapperBuilder 会将构建好的 ResultMap 对象 注册到 Configuration 对象的 resultMapRegistry 属性 (一个 ResultMapRegistry 对象) 中,使用 resultMapid 作为 key。

  • 2.3. 运行时,MyBatis 使用 ResultHandlerResultMap 进行结果集映射:

    在 MyBatis 运行时执行 SqlSession.selectList(), SqlSession.selectOne() 等查询方法时,MyBatis 会:

    1. 获取 MappedStatement 对象: 根据 Mapper 接口方法和方法名 (或 SQL 语句 ID) 找到对应的 MappedStatement 对象。
    2. 执行 SQL 查询: 使用 JDBC 执行 MappedStatement 中定义的 SQL 语句,获取 ResultSet (结果集)。
    3. 创建 ResultHandler 实例 (或使用默认的 DefaultResultHandler): ResultHandler 负责处理结果集。 MyBatis 通常使用默认的 DefaultResultHandler,也可以自定义 ResultHandler
    4. 获取 ResultMap 对象 (或 resultType):MappedStatement 对象中获取 ResultMap 对象 (如果配置了 resultMap) 或 resultType (如果配置了 resultType)。
    5. 逐行处理 ResultSet: ResultHandler 会逐行遍历 ResultSet,对于每一行数据:
      • 根据 ResultMap (或 resultType) 定义的映射规则,将 ResultSet 当前行的数据映射到 Java 对象。 这个映射过程会涉及到类型转换、属性赋值、关联对象/集合的创建和赋值等复杂操作。
      • 将映射后的 Java 对象添加到结果列表 (如果是 selectList) 或直接返回 (如果是 selectOne)。

    ResultHandlerResultMap 协同工作,完成了结果集到 Java 对象的映射过程。 ResultMap 定义映射规则,ResultHandler 负责执行映射操作。

总结:

  • XMLMapperBuilder 解析 SQL 语句时,会将 SQL 语句文本、参数映射、结果映射等信息封装成 MappedStatement 对象MappedStatement 是 MyBatis 运行时可执行的 SQL 对象。
  • XMLMapperBuilder 解析 <resultMap> 元素时,会构建 ResultMap 对象ResultMap 对象定义了结果集映射规则,但本身不执行映射操作。
  • ResultHandler 接口及其实现类 才是真正负责结果集映射的处理器。 MyBatis 运行时使用 ResultHandlerResultMap 协同工作,将查询结果集逐行映射到 Java 对象。
  • XMLMapperBuilder 的解析工作为 MyBatis 运行时执行 SQL 和进行结果集映射提供了必要的配置信息和对象模型。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/898321.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

咖啡点单小程序毕业设计(JAVA+SpringBoot+微信小程序+完整源码+论文)

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 随着社会的快速发展和…

003-掌控命令行-CLI11-C++开源库108杰

首选的现代C风格命令行参数解析器! &#xff08;本课程包含两段教学视频。&#xff09; 以文件对象监控程序为实例&#xff0c;五分钟实现从命令行读入多个监控目标路径&#xff1b;区分两大时机&#xff0c;学习 CLI11 构建与解析参数两大场景下的异常处理&#xff1b;区分三…

【leetcode hot 100 124】二叉树中的最大路径和

解法一&#xff1a;&#xff08;递归&#xff09;考虑实现一个简化的函数 maxGain(node)&#xff0c;该函数计算二叉树中的一个节点的最大贡献值&#xff0c;具体而言&#xff0c;就是在以该节点为根节点的子树中寻找以该节点为起点的一条路径&#xff0c;使得该路径上的节点值…

谱分析方法

前言 本文隶属于专栏《机器学习数学通关指南》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和参考文献请见《机器学习数学通关指南》 ima 知识库 知识库广场搜索&#…

在图像/视频中裁剪出人脸区域

1. 在图像中裁剪人脸区域 import face_alignment import skimage.io import numpy from argparse import ArgumentParser from skimage import img_as_ubyte from skimage.transform import resize from tqdm import tqdm import os import numpy as np import warnings warni…

【软考-架构】11.3、设计模式-新

✨资料&文章更新✨ GitHub地址&#xff1a;https://github.com/tyronczt/system_architect 文章目录 项目中的应用设计模式创建型设计模式结构型设计模式行为型设计模式 &#x1f4af;考试真题题外话 项目中的应用 在实际项目中&#xff0c;我应用过多种设计模式来解决不同…

使用Redis如何实现分布式锁?(超卖)

分布式锁概念 在多线程环境下&#xff0c;为了保证数据的线程安全&#xff0c;锁保证同一时刻&#xff0c;只有一个可以访问和更新共享数据。在单机系统我们可以使用 synchronized 锁、Lock 锁保证线程安全。 synchronized 锁是 Java 提供的一种内置锁&#xff0c;在单个 JVM …

Linux的Shell编程

一、什么是Shell 1、为什么要学习Shell Linux运维工程师在进行服务器集群管理时&#xff0c;需要编写Shell程序来进行服务器管理。 对于JavaEE和Python程序员来说&#xff0c;工作的需要。Boss会要求你编写一些Shell脚本进行程序或者是服务器的维护&#xff0c;比如编写一个…

使用React和google gemini api 打造一个google gemini应用

实现一个简单的聊天应用&#xff0c;用户可以通过输入问题或点击“Surprise me”按钮获取随机问题&#xff0c;并从后端API获取回答。 import { useState } from "react"; function App() {const [ value, setValue] useState(""); // 存储用户输入的问题…

深入探讨TK矩阵系统:创新的TikTok运营工具

TK矩阵的应用场景 TK矩阵系统适用于多个场景&#xff0c;尤其是在以下几个方面有显著优势&#xff1a; 批量账号管理与内容发布&#xff1a;对于需要管理多个TikTok账号的内容创作者或营销人员&#xff0c;TK矩阵提供了高效的账号管理工具&#xff0c;支持批量发布视频、评论、…

MTK Android12 应用在最顶端时,禁止拉起其他某个应用(一)

1、需求 近期&#xff0c;客户要求应用在最顶端时&#xff0c;禁止拉起其他某个应用2、解决方法 diff --git a/frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java b/frameworks/base/services/core/java/com/android/server/wm/ActivityStarte…

论文阅读笔记:Deep Unsupervised Learning using Nonequilibrium Thermodynamics

1、来源 论文连接1&#xff1a;http://ganguli-gang.stanford.edu/pdf/DeepUnsupDiffusion.pdf 论文连接2(带appendix)&#xff1a;https://arxiv.org/pdf/1503.03585v7 代码链接&#xff1a;https://github.com/Sohl-Dickstein/Diffusion-Probabilistic-Models 代码的环境配置…

7种数据结构

7种数据结构 顺序表sqlite.hseqlite.c 单链表linklist.clinklist.h 双链表doulinklist.cdoulinklist.h 链式栈linkstack.clinkstack.h 队列SeqQueue.cSeqQueue.h 树tree.c 哈希表hash.c 顺序表 sqlite.h #ifndef __SEQLIST_H__ #define __SEQLIST_H__ typedef struct person…

Linux 查看及测试网络命令

使用 ifconfig 命令查看网络接口地址 查看指定的网络接口信息 执行 ifconfig ens33 命令可以只查看网卡 ens33 的配置信息

ABAP语言的动态编程(4) - 综合案例:管理费用明细表

本篇来实现一个综合案例&#xff1a;管理费用明细表。报表在实际项目中&#xff0c;也有一定的参考意义&#xff0c;一方面展示类似的报表&#xff0c;比如管理费用、研发费用等费用的明细&#xff0c;使用业务比较习惯的展示格式&#xff1b;另一方面正好综合运用前面学习的动…

【Redis】Redis的数据删除(过期)策略,数据淘汰策略。

如果问到&#xff1a;假如Redis的key过期之后&#xff0c;会立即删除吗&#xff1f; 其实就是想问数据删除(过期)策略。 如果面试官问到&#xff1a;如果缓存过多&#xff0c;内存是有限的&#xff0c;内存被占满了怎么办&#xff1f; 其实就是问&#xff1a;数据的淘汰策略。…

Linux配置yum仓库,服务控制,防火墙

一、yum仓库 1.在安装软件时&#xff0c;首先第一步就是要考虑软件的版本的问题&#xff01; 2.软件的安装&#xff1a;最安全可靠的方法就是去软件对应的官网上查看安装手册&#xff08;包括的软件的下载&#xff09; 红帽系软件安装的常见的3种方式 &#xff08;1&#x…

[从零开始学习JAVA] Stream流

前言&#xff1a; 本文我们将学习Stream流&#xff0c;他就像流水线一样&#xff0c;可以对我们要处理的对象进行逐步处理&#xff0c;最终达到我们想要的效果&#xff0c;是JAVA中的一大好帮手&#xff0c;值得我们了解和掌握。&#xff08;通常和lambda 匿名内部类 方法引用相…

设计模式(创建型)-抽象工厂模式

摘要 在软件开发的复杂世界中,设计模式作为解决常见问题的最佳实践方案,一直扮演着至关重要的角色。抽象工厂模式,作为一种强大的创建型设计模式,在处理创建一系列或相关依赖对象的场景时,展现出了独特的优势和灵活性。它通过提供一个创建对象的接口,让开发者能够在不指定…

【JavaEE】-- SpringBoot快速上手

文章目录 1. Maven1.1 什么是Maven1.2 为什么要学Maven1.3 创建一个Maven项目1.4 Maven核心功能1.4.1 项目创建1.4.2 依赖管理1.4.3 Maven Help插件 1.5 Maven仓库1.5.1 本地仓库1.5.2 中央仓库1.5.3 私有服务器&#xff08;私服&#xff09; 1.6 Maven设置国内源1.6.1 配置当前…