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.pswp.cn/news/898321.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/898321.shtml
英文地址,請注明出處:http://en.pswp.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 配置當前…