有關MyBatis的動態SQL

有關MyBatis動態SQL

MyBatis動態SQL是一種根據不同條件靈活拼接SQL語句的技術,基于OGNL表達式實現。動態 SQL 大大減少了編寫代碼的工作量,更體現了 MyBatis 的靈活性、高度可配置性和可維護性。

1.什么是動態SQL?

動態sql可以在一些需要靈活拼接sql語句的場景中使用,作用是根據一些條件,拼接出需要的sql語句。

動態 SQL 是 MyBatis 的強大特性之一。在 JDBC 或其它類似的框架中,開發人員通常需要手動拼接 SQL 語句。根據不同的條件拼接 SQL 語句是一件極其痛苦的工作。而動態 SQL 恰好解決了這一問題,可以根據場景動態的構建查詢。

動態 SQL 只有幾個基本元素,與 JSTL 或 XML 文本處理器相似,十分簡單明了,大量的判斷都可以在 MyBatis 的映射 XML 文件里配置,以達到許多需要大量代碼才能實現的功能。

MyBatis 也可以在注解中配置 SQL,但是由于注解功能受限,且對于復雜的 SQL 語句來說可讀性差,所以使用較少。本教程不對它們進行介紹。

2.動態SQL的作用與原理

2.1 作用

  • 靈活拼接SQL:根據參數值動態添加或刪除SQL片段,例如條件查詢、批量操作、多分支選擇等場景
  • 簡化代碼:避免手動處理逗號、空格、WHERE/AND/OR等語法細節,提升代碼可讀性
  • 提高安全性:通過預編譯機制(#{})防止SQL注入,但需注意復雜邏輯下的潛在風險

2.2 執行原理

  • OGNL表達式:MyBatis使用OGNL(Object-Graph Navigation Language)從參數對象中解析條件值,判斷是否包含特定SQL片段

  • 動態解析流程

    ① XML中的SQL標簽(如<if> <where>、)被解析為SqlNode對象;

    ② 運行時根據參數值生成BoundSql對象,拼接最終SQL;

    ③ 核心類如OgnlExpressionEvaluator處理表達式計算,TrimSqlNodeWhereSqlNode

    等處理語法修剪;

3.常用動態SQL標簽及用法

MyBatis 的動態 SQL 包括以下幾種元素,如下表所示。

元素作用備注
if判斷語句單條件分支判斷
choose(when、otherwise)相當于 Java 中的 switch case 語句多條件分支判斷
trim、where輔助元素用于處理一些SQL拼裝問題
foreach循環語句在in語句等列舉條件常用
bind輔助元素拼接參數

3.1 <if>標簽

  • 功能:通過test屬性判斷條件是否成立,決定是否包含SQL片段。當判斷條件為 true 時,才會執行所包含的 SQL 語句

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

    <select id="selectUser">SELECT * FROM user<where><if test="name != null">AND name = #{name}</if><if test="age > 0">AND age = #{age}</if></where>
    </select>
    
    • 示例:可多個 if 語句同時使用。以下語句表示為可以按照student名稱(stu_name)或者stu_age進行模糊查詢。如果您不輸入名稱或年齡,則返回所有的student記錄。但是,如果你傳遞了任意一個參數,它就會返回與給定參數相匹配的記錄。
    <select id="select13" resultType="Student">select * from student where true<if test="name!=null">and stu_name='${name}'</if><if test="age!=null">and stu_age=${age}</if></select>
    

    注意:字符串比較需用toString()避免類型錯誤,如

    test="sex == '1'.toString()"
    

3.2 <where>標簽

  • 功能:自動生成WHERE子句,并去除首個條件的AND/OR前綴,避免語法錯誤。

  • if 語句中判斷條件為 true 時,where 關鍵字才會加入到組裝的 SQL 里面,否則就不加入。where 會檢索語句,它會將 where 后的第一個 SQL 條件語句的 AND 或者 OR 關鍵詞去掉。

  • 示例:

    <where><if test="name != null">name = #{name}</if><if test="age != null">AND age = #{age}</if>
    </where>
    
    • 最佳實踐:每個條件建議以AND/OR開頭,<where>會自動處理首前綴,where后面的意思是,如果后面if條件中有成立的語句,則加上where語句,如果沒有成立的條件語句,則不加where條件,第一個成立條件的語句,前面的and或者or自動刪除。

3.3 <trim>標簽

<trim prefix="前綴" suffix="后綴" prefixOverrides="忽略前綴字符" suffixOverrides="忽略后綴字符">SQL語句
</trim>
  • 功能:自定義前綴/后綴的添加或刪除,適用于復雜場景。
  • 屬性prefix(添加前綴)、suffix(添加后綴)、prefixOverrides(刪除前綴)、suffixOverrides(刪除后綴)。

trim 中屬性說明如下。

屬性描述
prefix給SQL語句拼接的前綴,為 trim 包含的內容加上前綴
suffix給SQL語句拼接的后綴,為 trim 包含的內容加上后綴
prefixOverrides去除 SQL 語句前面的關鍵字或字符,該關鍵字或者字符由 prefixOverrides 屬性指定。
suffixOverrides去除 SQL 語句后面的關鍵字或者字符,該關鍵字或者字符由 suffixOverrides 屬性指定。
  • 示例:替代<where>實現相同功能:

    <trim prefix="WHERE" prefixOverrides="AND |OR "><if test="name != null">AND name = #{name}</if>
    </trim>
    

3.4 <choose><when><otherwise>標簽

  • 功能:實現多分支選擇邏輯,類似Java的switch-case-default

  • <choose><when test="判斷條件1">SQL語句1</when><when test="判斷條件2">SQL語句2</when><when test="判斷條件3">SQL語句3</when><otherwise>SQL語句4</otherwise>
    </choose>
    
  • 示例:

    <choose><when test="name != null">AND name = #{name}</when><when test="age != null">AND age = #{age}</when><otherwise>AND status = 1</otherwise>
    </choose>
    

3.5 <foreach>標簽

對于一些 SQL 語句中含有 in 條件,需要迭代條件集合來生成的情況,可以使用 foreach 來實現 SQL 條件的迭代。

<foreach item="item" index="index" collection="list|array|map key" open="(" separator="," close=")">參數值
</foreach>  

參數說明:

foreach 標簽主要有以下屬性,說明如下。

  • item:表示集合中每一個元素進行迭代時的別名。
  • index:指定一個名字,表示在迭代過程中每次迭代到的位置。
  • open:表示該語句以什么開始(既然是 in 條件語句,所以必然以(開始)。
  • separator:表示在每次進行迭代之間以什么符號作為分隔符(既然是 in 條件語句,所以必然以,作為分隔符)。
  • close:表示該語句以什么結束(既然是 in 條件語句,所以必然以)開始)。

使用 foreach 標簽時,最關鍵、最容易出錯的是 collection 屬性,該屬性是必選的,但在不同情況下該屬性的值是不一樣的,主要有以下 3 種情況:

  • 如果傳入的是單參數且參數類型是一個 List,collection 屬性值為 list。
  • 如果傳入的是單參數且參數類型是一個 array 數組,collection 的屬性值為 array。
  • 如果傳入的參數是多個,需要把它們封裝成一個 Map,當然單參數也可以封裝成 Map。Map 的 key 是參數名,collection 屬性值是傳入的 List 或 array 對象在自己封裝的 Map 中的 key。
  • 功能:遍歷集合(如List、Array),生成批量操作的SQL,常用于IN語句或批量插入。

  • 示例:根據ID列表查詢用戶:

    SELECT * FROM user WHERE id IN
    <foreach collection="idList" item="id" open="(" separator="," close=")">#{id}
    </foreach>
    

3.6 <set>標簽

  • 功能:在更新操作中動態生成SET子句,自動去除末尾逗號。

  • 示例:

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

3.7 bind標簽

每個數據庫的拼接函數或連接符號都不同,例如 MySQL 的 concat 函數、Oracle 的連接符號“||”等。這樣 SQL 映射文件就需要根據不同的數據庫提供不同的實現,顯然比較麻煩,且不利于代碼的移植。幸運的是,MyBatis 提供了 bind 標簽來解決這一問題。

bind 標簽可以通過 OGNL 表達式自定義一個上下文變量。

比如,按照名稱進行模糊查詢,SQL 映射文件如下。

<select id="select14e" resultType="Student"><bind name="myvalue" value="'%'+stu_name+'%'" />SELECT *FROM studentWHERE stu_name like #{myvalue}
</select>            

bind 元素屬性如下:

  • value:對應傳入實體類的某個字段,可以進行字符串拼接等特殊處理。
  • name:給對應參數取的別名。

以上代碼中的“_parameter”代表傳遞進來的參數,它和通配符連接后,賦給了 pattern,然后就可以在 select 語句中使用這個變量進行模糊查詢,不管是 MySQL 數據庫還是 Oracle 數據庫都可以使用這樣的語句,提高了可移植性。

4.使用建議與注意事項

  1. 優先使用<where><set>:避免手動添加1=1或處理逗號,提高代碼簡潔性

  2. 模糊查詢優化:使用<bind>標簽統一處理模糊匹配,如<bind name="nameLike" value="'%' + name + '%'" />,解決不同數據庫的語法差異

  3. 性能考量:動態SQL可能影響執行計劃優化,復雜條件建議結合索引設計使用

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

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

相關文章

react使用拖拽,縮放組件,采用react-rnd解決 -完整版

屏幕錄制2025-03-10 10.16.06 以下代碼僅提供左側可視化區域 右側數據根據你們的存儲數據來 大家直接看Rnd標簽設置的屬性即可&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; /*** 用戶拖拽水印的最終位置信息*/ export interface ProductWatermarkValue {wat…

Spring Cloud之遠程調用OpenFeign參數傳遞

目錄 OpenFeign參數傳遞 傳遞單個參數 傳遞多個參數 傳遞對象 傳遞JSON OpenFeign參數傳遞 傳遞單個參數 服務提供方product-service RequestMapping("/product") RestController public class ProductController {Autowiredprivate ProductService productSe…

每日一練之移除鏈表元素

題目&#xff1a; 畫圖解析&#xff1a; 方法&#xff1a;雙指針 解答代碼&#xff08;注&#xff1a;解答代碼帶解析&#xff09;&#xff1a; //題目給的結構體 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* }…

從零開始的python學習(五)P75+P76+P77+P78+P79+P80

本文章記錄觀看B站python教程學習筆記和實踐感悟&#xff0c;視頻鏈接&#xff1a;【花了2萬多買的Python教程全套&#xff0c;現在分享給大家&#xff0c;入門到精通(Python全棧開發教程)】 https://www.bilibili.com/video/BV1wD4y1o7AS/?p6&share_sourcecopy_web&v…

基于SpringBoot實現旅游酒店平臺功能八

一、前言介紹&#xff1a; 1.1 項目摘要 隨著社會的快速發展和人民生活水平的不斷提高&#xff0c;旅游已經成為人們休閑娛樂的重要方式之一。人們越來越注重生活的品質和精神文化的追求&#xff0c;旅游需求呈現出爆發式增長。這種增長不僅體現在旅游人數的增加上&#xff0…

FastAPI 分頁模塊實現詳解

1. 簡介 本文詳細介紹了一個基于 FastAPI 框架的通用分頁處理模塊的實現。該模塊提供了標準的分頁參數處理、數據切片和響應格式化功能&#xff0c;可以輕松地集成到任何 FastAPI 項目中。 2. 代碼實現 2.1 導入必要的模塊 首先&#xff0c;我們需要導入所需的模塊&#xf…

Java 學習記錄:基礎到進階之路(一)

今天&#xff0c;讓我們深入到 Java 項目構建、基礎語法及核心編程概念的領域&#xff0c;一探究竟。 軟件安裝及環境配置請查看之前更新的博客有著詳細的介紹&#xff1a; IDEA軟件安裝&環境配置&中文插件-CSDN博客 目錄 1.Java 項目構建基礎 1.項目中的 SRC 目錄…

Yashan DB 對象管理

一、什么是數據庫對象 數據庫對象是數據庫里面用來存儲和指向數據的各種概念和結構的總稱。數據庫支持的對象包括&#xff1a; ? 表&#xff1a;表是一個邏輯概念&#xff0c;是數據庫組織管理數據的基本單位。 ? 索引&#xff1a;索引是建立在表上的邏輯對象&#xff0c;索…

deepseek 3FS編譯

3FS在ubuntu22.04下的編譯&#xff08;記錄下編譯過程&#xff0c;方便后續使用&#xff09; 環境信息 OS ubuntu 22.04內核版本 6.8.0-52-genericlibfuse 3.16.1rust 1.75.0FoundationDB 7.1.66meson 1.0.0ninja 1.10.1 libfuse編譯 以下建議均在root下執行 pip3 install…

python-uiautomator2 安裝教程

目錄 一、簡介 二、支持平臺及語言 三、工作原理 四、安裝 一、簡介 uiautomator2是一個python庫&#xff0c;用于Android的UI自動化測試&#xff0c;其底層基于Google uiautomator&#xff0c;Google提供的uiautomator庫可以獲取屏幕上任意一個APP的任意一個控件屬性&…

無頭瀏覽器與請求簽名技術-Cloudflare防護

在實際數據采集實踐中&#xff0c;許多目標網站&#xff08;例如 Amazon&#xff09;都會采用 Cloudflare 等防護措施&#xff0c;防止機器人和非正常流量。本文將分享一個故障場景下的排查與改進方案&#xff0c;講述如何利用無頭瀏覽器、請求簽名技術以及爬蟲代理 IP來實現數…

Spring Cloud之注冊中心之Nacos健康監測和環境隔離

目錄 Nacos健康檢查 兩種健康檢查機制 Nacos服務類型實例 Nacos環境隔離 創建namespace 配置namespace Nacos健康檢查 兩種健康檢查機制 Nacos作為注冊中?, 需要感知服務的健康狀態, 才能為服務調??提供良好的服務. Nacos 中提供了兩種健康檢查機制&#xff1a; 客?…

Vue3實戰學習(Element-Plus常用組件的使用(輸入框、下拉框、單選框多選框、el-image圖片))(上)(5)

目錄 一、Vue3工程環境配置、項目基礎腳手架搭建、Vue3基礎語法、Vue3集成Element-Plus的詳細教程。(博客鏈接如下) 二、Element-Plus常用組件使用。 &#xff08;1&#xff09;el-input。(input輸入框) <1>正常狀態的el-input。 <2>el-input的disable狀態。 <3…

微服務——網關、網關登錄校驗、OpenFeign傳遞共享信息、Nacos共享配置以及熱更新、動態路由

之前學習了Nacos&#xff0c;用于發現并注冊、管理項目里所有的微服務&#xff0c;而OpenFeign簡化微服務之間的通信&#xff0c;而為了使得前端可以使用微服務項目里的每一個微服務的接口&#xff0c;就應該將所有微服務的接口管理起來方便前端調用&#xff0c;所以有了網關。…

2025年3月11日(有限元牛頓迭代法:通俗講解與示例)

牛頓迭代法的正確流程解釋 是的&#xff0c;你的理解基本正確&#xff01;但需要更準確地描述內外力的關系和迭代邏輯。以下是更清晰的步驟說明&#xff1a; 核心流程&#xff08;修正版&#xff09; 假設已知 外力 ( F_{\text{ext}} )&#xff08;如2000 N&#xff09;&…

爬蟲的精準識別:基于 User-Agent 的正則實現

&#x1f9d1; 博主簡介&#xff1a;CSDN博客專家&#xff0c;歷代文學網&#xff08;PC端可以訪問&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移動端可微信小程序搜索“歷代文學”&#xff09;總架構師&#xff0c;15年工作經驗&#xff0c;精通Java編…

【AI大模型】LLM訓練deepseek如何識別視頻

要讓像DeepSeek這樣的大語言模型&#xff08;LLM&#xff09;具備視頻識別能力&#xff0c;需要結合多模態學習技術&#xff0c;將視覺信息與文本語義進行融合。以下是實現這一目標的關鍵步驟和技術要點&#xff1a; --- 一、視頻識別的核心挑戰 1. 多模態數據&#xff1a;視頻…

【物聯網-以太網-W5500】

物聯網-以太網-W5500 ■ W5500-簡介■■■■ ■ W5500-簡介 ■ ■ ■ ■

centos linux安裝mysql8 重置密碼 遠程連接

1. 下載并安裝 MySQL Yum 倉庫 從 MySQL 官方網站下載并安裝 Yum 倉庫配置文件。 # 下載MySQL 8.0的Yum倉庫包 wget https://dev.mysql.com/get/mysql80-community-release-el7-5.noarch.rpm # 安裝Yum倉庫包 sudo rpm -ivh mysql80-community-release-el7-5.noarch.rpm2. 啟…

C++【類和對象】(超詳細!!!)

C【類和對象】 1.運算符重載2.賦值運算符重載3.日期類的實現 1.運算符重載 (1).C規定類類型運算符使用時&#xff0c;必須轉換成調用運算符重載。 (2).運算符重載是具有特殊名字的函數&#xff0c;名字等于operator加需要使用的運算符&#xff0c;具有返回類型和參數列表及函數…