MyBatis 動態查詢語句詳解:讓 SQL 更靈活可控

MyBatis 動態查詢語句詳解:讓 SQL 更靈活可控

在日常的數據庫操作中,我們經常會遇到需要根據不同條件拼接 SQL 語句的場景。比如查詢用戶時,可能需要根據姓名、年齡、性別等多個條件進行篩選,而這些條件往往是動態變化的 —— 有時需要按姓名查,有時需要按年齡查,有時又需要組合多個條件。如果手動拼接 SQL,不僅容易出錯,還會讓代碼變得臃腫難維護。MyBatis 的動態查詢語句正是為解決這一問題而生,它能根據參數的不同自動拼接 SQL 片段,讓 SQL 編寫更加靈活高效。

一、動態查詢的核心價值

動態查詢是 MyBatis 的核心特性之一,它允許我們在 XML 映射文件或注解中,通過一系列標簽控制 SQL 片段的拼接邏輯。其核心價值體現在三個方面:

  • 減少冗余代碼:無需為不同條件組合編寫大量重復的 SQL 語句。

  • 避免 SQL 注入風險:MyBatis 的動態標簽會自動處理參數拼接,比手動字符串拼接更安全。

  • 提升代碼可讀性:將條件判斷邏輯與 SQL 語句分離,讓業務邏輯更清晰。

舉個簡單的例子:查詢用戶列表時,可能需要根據姓名(name)和年齡(age)篩選。如果沒有動態查詢,我們可能需要編寫 3 條 SQL(只查 name、只查 age、同時查 name 和 age);而有了動態查詢,1 條 SQL 就能搞定所有場景。

二、常用動態查詢標簽詳解

MyBatis 提供了一套完整的動態 SQL 標簽,涵蓋了大多數條件判斷場景。下面介紹最常用的幾個標簽及其用法。

1. <if>:條件判斷的基礎

<if>標簽是動態查詢中最常用的標簽,用于根據參數值決定是否拼接某個 SQL 片段。其語法如下:

<if test="條件表達式">SQL片段
</if>

示例:根據姓名和年齡查詢用戶

<select id="selectUser" resultType="User">SELECT * FROM userWHERE 1=1<if test="name != null and name != ''">AND name LIKE CONCAT('%', #{name}, '%')</if><if test="age != null">AND age = #{age}</if>
</select>

這里的WHERE 1=1是為了避免當所有<if>條件都不滿足時,SQL 出現WHERE后無內容的語法錯誤。當name不為空時,會拼接AND name LIKE ...;當age不為空時,會拼接AND age = ...

2. <choose>+<when>+<otherwise>:多條件分支選擇

當需要實現 “多條件選其一” 的邏輯時,可以使用<choose>標簽(類似 Java 中的switch),配合<when>(類似case)和<otherwise>(類似default)標簽使用。

示例:優先按姓名查詢,若姓名為空則按年齡查詢,否則查詢所有

<select id="selectUserByCondition" resultType="User">SELECT * FROM user<where><choose><when test="name != null and name != ''">name LIKE CONCAT('%', #{name}, '%')</when><when test="age != null">age = #{age}</when><otherwise>1=1  <!-- 當所有條件都不滿足時,查詢所有數據 --></otherwise></choose></where>
</select>

<where>標簽會自動處理 SQL 片段開頭的ANDOR,避免語法錯誤。比如當第一個<when>條件滿足時,拼接的name LIKE ...前不會有多余的AND

3. <trim>:自定義 SQL 片段拼接規則

<trim>標簽可以通過屬性自定義 SQL 片段的前綴、后綴,以及需要去掉的前綴或后綴字符,比<where>更靈活。常用屬性:

  • prefix:給拼接的 SQL 片段添加前綴

  • suffix:給拼接的 SQL 片段添加后綴

  • prefixOverrides:去掉片段開頭的指定字符

  • suffixOverrides:去掉片段結尾的指定字符

示例:用<trim>實現<where>的功能

<select id="selectUser" resultType="User">SELECT * FROM user<trim prefix="WHERE" prefixOverrides="AND | OR"><if test="name != null and name != ''">AND name LIKE CONCAT('%', #{name}, '%')</if><if test="age != null">AND age = #{age}</if></trim>
</select>

<trim>內部有內容時,會添加WHERE前綴,并去掉開頭的ANDOR,效果與<where>一致。

4. <foreach>:遍歷集合參數

當需要處理批量操作(如IN查詢、批量插入)時,<foreach>標簽非常有用。它可以遍歷數組或集合,將元素拼接成 SQL 片段。常用屬性:

  • collection:指定要遍歷的集合參數名(如listarray@Param定義的名稱)

  • item:遍歷過程中每個元素的別名

  • index:遍歷索引(可選)

  • open:片段開頭的字符

  • close:片段結尾的字符

  • separator:元素之間的分隔符

示例 1:批量查詢(IN 語句)

<select id="selectUserByIds" resultType="User">SELECT * FROM userWHERE id IN<foreach collection="ids" item="id" open="(" close=")" separator=",">#{id}</foreach>
</select>

ids[1,2,3]時,會拼接成WHERE id IN (1,2,3)

示例 2:批量插入

<insert id="batchInsertUser">INSERT INTO user (name, age) VALUES<foreach collection="list" item="user" separator=",">(#{user.name}, #{user.age})</foreach>
</insert>

list包含 3 個 User 對象時,會拼接成INSERT INTO user (name, age) VALUES (?,?), (?,?), (?,?)

5. <set>:更新語句的動態處理

在更新操作中,<set>標簽用于動態拼接SET子句,會自動去掉多余的逗號。

示例:動態更新用戶信息

<update id="updateUser">UPDATE user<set><if test="name != null and name != ''">name = #{name},</if><if test="age != null">age = #{age},</if></set>WHERE id = #{id}
</update>

nameage都不為空時,會拼接成UPDATE user SET name = ?, age = ? WHERE id = ?,自動去掉age = ?后的逗號。

三、實戰案例:綜合運用動態標簽

下面通過一個復雜案例,展示如何綜合運用上述標簽實現多條件組合查詢。

需求:查詢商品列表,支持按分類(category)、價格范圍(minPrice、maxPrice)、是否庫存(hasStock)篩選,且支持排序(sortField、sortType)。

Mapper 接口

List<Product> selectProducts(@Param("category") String category,@Param("minPrice") BigDecimal minPrice,@Param("maxPrice") BigDecimal maxPrice,@Param("hasStock") Boolean hasStock,@Param("sortField") String sortField,@Param("sortType") String sortType
);

XML 映射文件

<select id="selectProducts" resultType="Product">SELECT * FROM product<trim prefix="WHERE" prefixOverrides="AND | OR"><if test="category != null and category != ''">AND category = #{category}</if><if test="minPrice != null">AND price >= #{minPrice}</if><if test="maxPrice != null">AND price <= #{maxPrice}</if><if test="hasStock != null">AND stock > 0</if></trim><if test="sortField != null and sortField != '' and sortType != null">ORDER BY ${sortField} ${sortType}  <!-- 排序字段用${},注意SQL注入風險 --></if>
</select>

說明

  • <trim>處理查詢條件,避免多余的AND

  • <if>判斷每個篩選條件是否生效

  • 排序部分通過<if>控制是否拼接ORDER BY,注意排序字段使用${}(因為#{}會加引號,導致語法錯誤),但需確保sortFieldsortType是可信參數,避免 SQL 注入。

四、注意事項與最佳實踐

  1. 參數判斷的細節
  • 字符串判斷:test="name != null and name != ''"(先判斷非空,再判斷非空字符串)

  • 數字判斷:test="age != null"(無需判斷空字符串)

  • 布爾值判斷:test="hasStock != null and hasStock"(直接用參數名判斷 true/false)

  1. SQL 注入風險
  • 動態 SQL 中,#{}會自動加引號,適合參數值;${}直接拼接 SQL,適合表名、字段名等,但需嚴格校驗參數,避免注入。

  • 排序、分組等場景需用${}時,建議限制可選值(如sortField只能是idprice等已知字段)。

  1. 代碼可讀性
  • 復雜動態 SQL 建議拆分到 XML 文件,而非注解中

  • 給參數添加@Param注解,避免使用arg0arg1

  • 合理使用換行和縮進,保持 SQL 結構清晰

  1. 性能優化
  • 避免過度復雜的動態 SQL,否則可能影響數據庫優化器生成執行計劃

  • 頻繁執行的動態 SQL,建議通過 MyBatis 的二級緩存緩存結果

五、總結

MyBatis 的動態查詢語句通過<if><choose><foreach>等標簽,完美解決了 SQL 條件動態拼接的問題,讓開發者能更專注于業務邏輯而非 SQL 語法細節。掌握這些標簽的用法,不僅能減少代碼量,還能提升系統的靈活性和可維護性。

在實際開發中,建議結合具體業務場景選擇合適的標簽,同時注意參數校驗和 SQL 注入風險,讓動態 SQL 成為提升開發效率的利器而非隱患。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/93848.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/93848.shtml
英文地址,請注明出處:http://en.pswp.cn/web/93848.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java基礎語法three

一、一維數組一維數組初始化數據類型[] 數組名new 數據類型[數組長度]//動態初始化數據類型[] 數組名new 數據類型[]{值}//靜態初始化數據類型[] 數組名{值}數組長度一旦確定&#xff0c;就不可更改。數組是序排序&#xff1b;數組屬于引用數據類型的變量&#xff0c;數組的元素…

【數據結構】排序算法全解析:概念與接口

1.排序的概念及其運用 1.1 排序的概念 排序&#xff1a;所謂排序&#xff0c;就是使一串記錄&#xff0c;按照其中的某個或某些關鍵字的大小&#xff0c;遞增或遞減的排列起來的操作。 穩定性&#xff1a;假定在待排序的記錄序列中&#xff0c;存在多個具有相同的關鍵字的…

在 CentOS 7 上使用 LAMP 架構部署 WordPress

CentOS 7 LAMP 架構部署 WordPress全步驟本文將詳細介紹如何在 CentOS 7 系統上通過 LAMP&#xff08;Linux Apache MariaDB PHP&#xff09;架構部署 WordPress 博客平臺。 在CentOS 7上基于LAMP架構部署WordPress 一、系統基礎配置 1. 修改主機名&#xff08;本機IP&#…

Node.js導入MongoDB具體操作

在Node.js應用程序中&#xff0c;導入MongoDB是一項常見任務。本文將詳細介紹如何在Node.js中連接和操作MongoDB數據庫&#xff0c;包括安裝必要的包、配置連接、執行基本的CRUD操作等步驟。1. 安裝必要的包首先&#xff0c;確保你已經安裝了Node.js和npm。然后&#xff0c;通過…

HTML--pre標簽的作用

原文網址&#xff1a;HTML--pre標簽的作用-CSDN博客 簡介 本文介紹HTML里pre標簽的作用。 <pre> 元素表示預定義格式文本。里邊的文本會保留原格式&#xff0c;以等寬字體的形式展現出來&#xff0c;文本中的空白符&#xff08;比如空格和換行符&#xff09;都會顯示出…

機器學習--數據預處理

目錄 一、數據清洗&#xff1a;讓數據純凈如新 1、缺失值處理&#xff1a; 2、異常值處理 3、重復值處理 二、數據變換&#xff1a;重塑數據的 “形狀” 1、歸一化 2、標準化 三、總結與展望 機器學習小白必看&#xff1a;數據預處理實戰筆記 最近投身于機器學習的學習…

Python 數據可視化:Matplotlib 與 Seaborn 實戰

Python 數據可視化&#xff1a;Matplotlib 與 Seaborn 實戰????在當今數據驅動的時代&#xff0c;數據可視化成為了理解和傳達數據信息的關鍵手段。Python 作為一門強大的編程語言&#xff0c;擁有豐富的數據可視化庫&#xff0c;其中 Matplotlib 和 Seaborn 尤為突出。本文…

計算機網絡技術學習-day4《路由器配置》

目錄 一、路由器基礎認知 1. 路由器的核心功能 2. 路由器與交換機的區別 二、路由器配置基礎操作 1. CLI&#xff08;命令行界面&#xff09;模式體系 2. 基礎配置命令示例 &#xff08;1&#xff09;基礎信息配置 &#xff08;2&#xff09;接口IP地址配置&#xff08;…

IDEA(十四) IntelliJ Idea 常用快捷鍵(Mac)

目錄準備&#xff1a;Mac鍵盤符號和修飾鍵說明一、編輯類快捷鍵二、Search/Replace&#xff08;查詢/替換&#xff09;三、編譯、運行四、debug 調試五、Navigation&#xff08;導航&#xff09;六、Refactoring&#xff08;重構&#xff09;七、VCS/Local History八、Live Tem…

八月月報丨MaxKB在教育及教學科研領域的應用進展

在2025年5月的“MaxKB用戶應用月度報告”中&#xff0c;我們對MaxKB開源智能體平臺在教育行業的典型應用場景進行了總結。MaxKB在教育行業的應用主要集中在教學輔助、學術研究、校園服務、行政辦公、財務管理、招生等場景。 目前&#xff0c;“DeepSeekMaxKB”的組合正在被包括…

一周學會Matplotlib3 Python 數據可視化-繪制自相關圖

鋒哥原創的Matplotlib3 Python數據可視化視頻教程&#xff1a; 2026版 Matplotlib3 Python 數據可視化 視頻教程(無廢話版) 玩命更新中~_嗶哩嗶哩_bilibili 課程介紹 本課程講解利用python進行數據可視化 科研繪圖-Matplotlib&#xff0c;學習Matplotlib圖形參數基本設置&…

第三十三天(信號量)

非常非常非常.....的重要在共享內存的代碼里面p1.c實質是有問題lt._flag 1;//這里先置1if(c Q)sprintf(lt._buf,"quit");elsesprintf(lt._buf,"大家好&#xff0c;%d 我系渣渣輝. %d 是兄弟就來砍我吧!!! %d",i,i1,i2);while(*((int *)shmptr));//如果別…

Scikit-learn通關秘籍:從鳶尾花分類到房價預測

點擊 “AladdinEdu&#xff0c;同學們用得起的【H卡】算力平臺”&#xff0c;H卡級別算力&#xff0c;按量計費&#xff0c;靈活彈性&#xff0c;頂級配置&#xff0c;學生專屬優惠。 決策樹/SVM/KNN算法對比 模型評估指標解析 讀者收獲&#xff1a;掌握經典機器學習全流程 …

rsync + inotify 數據實時同步

rsync inotify 數據實時同步 一、rsync簡介 rsync是linux系統下的數據鏡像備份工具。使用快速增量備份工具Remote Sync可以遠程同步&#xff0c; 支持本地復制&#xff0c;或者與其他SSH、rsync主機同步 二、rsync三種命令 Rsync的命令格式常用的有以下三種&#xff1a;&#…

Linux基礎介紹-3——第一階段

文章目錄一、進程管理1.1 進程的基本概念1.2 常見管理命令1.3 進程優先級調整&#xff1a;nice 與 renice二、軟件包管理三、防火墻管理四、shell腳本五、xshell鏈接kali一、進程管理 1.1 進程的基本概念 進程是程序的動態執行實例&#xff0c;每個進程都有唯一的 PID&#x…

python 可迭代對象相關知識點

1. 什么是可迭代對象 (Iterable) 在 Python 里&#xff0c;可迭代對象指的是&#xff1a; &#x1f449; 能夠一次返回一個元素的對象&#xff0c;可以被 for 循環遍歷。 常見的可迭代對象有&#xff1a; 序列類型&#xff1a;list、tuple、str集合類型&#xff1a;set、dict&a…

ijkplayer Android 編譯

一、下載編譯庫文件1.1 編譯庫文件環境&#xff1a;ubuntu 20.04 版本liangtao:ffmpeg$lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 20.04.6 LTS Release: 20.04 Codename: focal1.2 項目源碼下載使用 git 下載 ijkplayer&#…

snn前向推理時間計算(處理器實現)

公式 Tinf(1?sparsity)number of synapsesnumber of sub-processorsSIMD ways T_{\text{inf}} \frac{(1-\text{sparsity})\times \text{number of synapses}} {\text{number of sub-processors}\times \text{SIMD ways}} Tinf?number of sub-processorsSIMD ways(1?sparsity…

Linux------《操作系統全景速覽:Windows·macOS·Linux·Unix 對比及 Linux 發行版實戰指南》

&#xff08;一&#xff09;常見操作系統&#xff08;system&#xff09;電腦&#xff1a;Windows,Macos,Linux,UnixWindows&#xff1a;微軟公司開發的一款桌面操作系統&#xff08;閉源系統&#xff09;。版本有dos&#xff0c;win98&#xff0c;win NT&#xff0c;win XP , …

Three.js 初級教程大全

本文檔旨在為初學者提供一個全面的 Three.js 入門指南。我們將從 Three.js 的基本概念開始&#xff0c;逐步介紹如何創建場景、添加物體、設置材質、使用光照和相機&#xff0c;以及如何實現簡單的動畫和交互。通過本教程&#xff0c;你將能夠掌握 Three.js 的核心知識&#xf…