MyBatis - XML 操作動態 SQL

目錄

1. 前言

2.?動態插入

2.1 if 標簽?

2.2 trim 標簽

2.2.1?注解完成動態 SQL

3. 動態查詢

3.1 添加 1 = 1

3.2 where 標簽

?4. 動態更新

4.1 set 標簽

?5. foreach 標簽

6. sql 標簽 & include 標簽


1. 前言

之前博文所講的 MyBatis SQL 操作, 都必須按照注解或者標簽中定義的 SQL 嚴格執行, 一個注解/標簽, 對應的是不同的 SQL 操作. 比如: 一個 select 注解中, 定義了?3 個字段, 那這個注解只能插入這三個列的值, 如果想要插入更多的列, 必須重新再寫一個注解.

而動態 SQL, 我們可以根據用戶輸入的值, 動態的進行字段的插入, 當用戶輸入這一字段的值時, 就插入這一字段. 當用戶沒有輸入這一字段的值時, 就不插入這一字段. 能夠完成不同條件下, 不同的 SQL 拼接.

注意: 本文主要通過 XML 完成動態 SQL!!?

2.?動態插入

2.1 if 標簽?

通過 if 標簽, 對傳入的參數的值進行判斷, 若未傳入相關列的值, 則不拼接該列的 SQL 片段.?

如下圖所示, 只有當傳入參數的值不為 null 時, 才會拼接該 SQL 片段.

注意: if 標簽, 判斷的是傳入的參數的值(#{} 中的參數), 即 java 屬性, 而不是數據庫字段!!

因此, 我們就可以通過這一個 insert 標簽對應的方法, 進行任意字段的插入:

但是, 當對最后一個字段傳入的值為 null 時, 錯誤就發生了:

這是因為最后一個字段?gender?的值為 null, 導致 if 標簽的判斷為 false, 因此 gender 字段的 SQL 沒有進行拼接, 導致倒數第二個字段 phone 后多了一個逗號(,), 拼接的內容是 "phone , "因此造成語法錯誤.

此時, 就需要 trim 標簽出馬了~~

2.2 trim 標簽

trim 標簽中有以下屬性:

  1. prefix: 表示整個語句塊, 以 prefix 的值作為前綴
  2. suffix: 表示整個語句塊, 以suffix的值作為后綴
  3. prefixOverrides: 表示整個語句塊要去除掉的前綴
  4. suffixOverrides: 表示整個語句塊要去除掉的后綴

有 trim 標簽, 就可以通過 prefixOverrides/suffixOverrides 屬性解決上文中由于沒有拼接最后一個字段, 導致倒數第二個字段后拼接了逗號(,)的問題, 并且還可以通過 prefix/suffix 屬性將 SQL 中的 "(" 和 ")" 自動拼接到 SQL 中:

?運行觀察結果:

<insert id="insertUser4">insert into user_info<trim prefix="(" suffix=")" prefixOverrides="," suffixOverrides=","><if test="username != null">username,</if><if test="password != null">password,</if><if test="age != null">age,</if><if test="phone != null">phone,</if><if test="gender != null">gender</if></trim>values<trim prefix="(" suffix=")" prefixOverrides="," suffixOverrides=","><if test="username != null">#{username},</if><if test="password != null">#{password},</if><if test="age != null">#{age},</if><if test="phone != null">#{phone},</if><if test="gender != null">#{gender}</if></trim></insert>

2.2.1?注解操作動態 SQL

上文是通過?XML 進行的動態 SQL?, 在注解中同樣也是可以的, 并且方式相同.

若要通過注解完成動態 SQL, 只需將上文?XML 中動態 SQL 的代碼, 以字符串的形式拼接到 <script> 標簽中即可.

    @Insert("<script>" +"insert into user_info " +"<trim prefix=\"(\" suffix=\")\" prefixOverrides=\",\" suffixOverrides=\",\">" +"<if test=\"username != null\">username,</if>" +"<if test=\"password != null\">password,</if>" +"<if test=\"age != null\">age,</if>" +"<if test=\"phone != null\">phone,</if>" +"<if test=\"gender != null\">gender</if>" +"</trim> values " +"<trim prefix=\"(\" suffix=\")\" prefixOverrides=\",\" suffixOverrides=\",\">" +"<if test=\"username != null\">#{username},</if>" +"<if test=\"password != null\">#{password},</if>" +"<if test=\"age != null\">#{age},</if>" +"<if test=\"phone != null\">#{phone},</if>" +"<if test=\"gender != null\">#{gender}</if>" +"</trim>" +"</script>")int insertUser4(UserInfo userInfo);

3. 動態查詢

進行 select 查詢操作時, 常常會用到 where 關鍵字進行條件查詢, 進行條件查詢時, 同樣也可以通過 if 標簽進行動態查詢:

但是, 當參數 phone 為 null 時, 就發生錯誤了:

出錯的原因很簡單: 因為?phone 屬性的值為 null, 導致 where 關鍵字后跟的是 "and gender", 導致 SQL 語法錯誤.

解決辦法很簡單, 使用 trim 標簽, 將 and 關鍵字去除即可:

但是, 當 phone 和 gender 兩個屬性都為 null 時, 問題又出現了:

這里錯誤的原因是: phone 和 gender 都為 null, 導致出現了多余的 where 關鍵字, 導致 SQL 語法錯誤.

解決方法有兩種:

  1. 添加 1 = 1, 保證?where 后有條件
  2. 使用 <where>, 去除 where 關鍵字

3.1 添加 1 = 1

在 where 關鍵字后添加 1 = 1, 保證 where 后有條件. 并在每條拼接的 SQL 片段前添加 and, 保證 SQL 片段可以進行拼接:?

<select id="selectByCondition" resultType="com.study.mybatis.model.UserInfo">select * from user_infowhere 1 = 1<if test="phone != null">and phone = #{phone}</if><if test="gender != null">and gender = #{gender}</if></select>

3.2 where 標簽

使用 where 標簽代替 where 關鍵字:

where 標簽有兩個作用:

  1. 當 where 標簽語塊內沒有內容時, 不會生成 where 關鍵字
  2. 當 where 標簽語塊內有查詢條件時, 會自動生成 where 關鍵字, 并且會去除最前面的 and 關鍵字

因此, 即使查詢條件全為 null, 或者第一個查詢條件前有 and 關鍵字, where 標簽都會幫我們解決這些問題:

但是, 在實際工作中, 要避免使用 where 標簽, 因為當我們遺漏傳入條件查詢的參數時, 程序也會正確執行, 而無任何條件限制的 select 是非常嚴重的!!

<select id="selectByCondition" resultType="com.study.mybatis.model.UserInfo">select * from user_info<where><if test="phone != null">phone = #{phone}</if><if test="gender != null">and gender = #{gender}</if></where>
</select>

?4. 動態更新

update 語句也可以結合 if 和 trim 標簽, 完成動態更新操作:

<update id="updateUser2">update user_infoset<trim suffixOverrides=","><if test="username != null">username = #{username},</if><if test="password != null">password = #{password},</if><if test="age != null">age = #{age}</if></trim>where id = #{id}</update>

4.1 set 標簽

除了上文將?if 和 trim 標簽結合完成動態的 update 操作外, 也可以使用 set 標簽來完成.

set 標簽的作用:

  1. 生成 set 關鍵字
  2. 去除多余的逗號(只能去除最后一個逗號)

<update id="updateUser3">update user_info<set><if test="username != null">username = #{username},</if><if test="password != null">password = #{password},</if><if test="age != null">age = #{age}</if></set>where id = #{id}</update>

?5. foreach 標簽

在進行數據庫操作時, 我們常會在一個條 SQL 語句中, 對數據批量的進行操作, 如下:

SELECT * FROM user_info where id = 1 or id = 2 or id = 3;INSERT into user_info (username, `password`) VALUES ('1', '1'), ('2', '2');UPDATE user_info set delete_flag = 1 WHERE id IN(1, 2, 3);DELETE from user_info WHERE id IN(4, 5, 6);

如果要通過 MyBatis 對數據進行批量處理, 就需要使用 foreach 標簽. \

使用 foreach 批量操作數據, 傳入的參數必定是一個集合(包括 Map).

foreach 標簽中有以下幾個關鍵屬性:

  1. collection?(必須):?指定要迭代的集合. (如果方法參數是 Listcollection 就是 List 的參數名)

  2. item?(必須):?指定迭代過程中元素的名稱.

  3. index?(可選):?表示集合中每個元素的索引

  4. separator?(可選):?指定每個元素之間的分隔符

  5. open?(可選):?循環開始前要添加的字符串. 通常用于在?IN?語句中添加左括號?(

  6. close?(可選):?循環結束后要添加的字符串. 通常用于在?IN?語句中添加右括號?)

<!--    DELETE from user_info WHERE id IN(1, 2, 3);--><delete id="deleteUser2">delete from user_info whereid in<foreach collection="ids" open="(" close=")" item="id" separator=",">#{id}</foreach></delete>
<!--    delete FROM user_info where id = 1 or id = 2 or id = 3;--><delete id="deleteUser3">delete from user_info where<foreach collection="ids" item="id" separator="or">id = #{id}</foreach></delete>
<!--    insert into user_info (username, `password`) VALUES ('1', '1'), ('2', '2');--><insert id="insertUser1">insert into user_info (username, password) values<foreach collection="userInfos" item="user" separator=",">(#{user.username}, #{user.password})</foreach></insert>

6. sql 標簽 & include 標簽

sql 標簽和 include 標簽通常搭配使用.

在 sql 標簽中定義一個 sql 片段, 并指定這個 sql 標簽的 id.

在其他任何標簽中, 就可以通過 include 標簽指定某個 sql 標簽的 id, 直接引用該 sql 標簽中的 sql 片段.

也就是說, 我們可以直接通過 sql 標簽的 id, 實現 sql 片段的復用.

注意:

SQL 標簽中可以定義任意的 SQL 片段(字符串), 不一定是可執行的 SQL !!


END?

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

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

相關文章

【最佳實踐】Go 責任鏈模式實現參數校驗

這里我們使用責任鏈模式來創建一個參數校驗的示例。在這個示例中&#xff0c;我們將實現一個簡單的責任鏈來校驗不同的參數條件。這種模式允許我們將多個校驗步驟串聯在一起&#xff0c;以便可以在不同的條件下進行靈活的校驗。 設計思路 接口定義 (Validator) 目的&#xff1…

深入理解Tomcat:Java Web服務器的安裝與配置

大家好&#xff01;今天我們來聊聊Java Web開發中最重要的工具之一——Apache Tomcat。Tomcat是一個開源的Java Servlet容器和Web服務器&#xff0c;它是運行Java Web應用程序的核心環境。無論是開發、測試還是部署Java Web應用&#xff0c;Tomcat都是不可或缺的工具。本文將詳…

小程序酒店:如何實現智能預訂與在線支付?

在移動互聯網快速發展的今天,酒店行業面臨著前所未有的機遇與挑戰。用戶需求日益多樣化,市場競爭愈發激烈,傳統酒店預訂方式已經難以滿足現代消費者的需求。而小程序作為一種輕量化、便捷化的移動應用形式,正在成為酒店行業數字化轉型的重要工具。通過小程序開發,酒店可以…

C#實現AES-CBC加密工具類(含完整源碼及使用教程)

一、AES-CBC加密應用場景 AES&#xff08;Advanced Encryption Standard&#xff09;作為全球公認的安全加密標準&#xff0c;廣泛使用在以下場景&#xff1a; API通信加密&#xff1a;保護HTTP接口傳輸的敏感數據&#xff08;如身份令牌、支付信息&#xff09;文件安全存儲&…

docker-compose部署MongoDB分片集群

前言 MongoDB 使用 keyFile 進行 節點間身份驗證,我們需要先創建一個 keyFile 并確保所有副本集的節點使用相同的 keyFile。 openssl rand -base64 756 > mongo-keyfile chmod 400 mongo-keyfiledocker-compose部署分片集群 無密碼方式 # docker-compose-mongodb.yml s…

3-003:在 MySQL 中建索引時需要注意哪些事項?

在 MySQL 中創建索引時&#xff0c;需要注意以下事項&#xff0c;以確保索引高效且合理&#xff1a; 1. 選擇合適的索引類型 主鍵索引&#xff08;PRIMARY KEY&#xff09;&#xff1a;每個表只能有一個&#xff0c;默認是聚簇索引。唯一索引&#xff08;UNIQUE&#xff09;&…

在 Linux 系統中,區分**磁盤(物理/虛擬存儲設備)和分區(磁盤的邏輯劃分)

在 Linux 系統中&#xff0c;區分**磁盤&#xff08;物理/虛擬存儲設備&#xff09;和分區&#xff08;磁盤的邏輯劃分&#xff09;**是管理存儲的基礎。以下是詳細的區分方法和操作示例&#xff1a; 一、通過設備命名規則區分 Linux 中磁盤和分區的命名遵循特定規則&#xff…

MongoDB中的游標(Cursor)

游標&#xff08;Cursor&#xff09;在MongoDB中是一個重要的概念&#xff0c;它用于逐條遍歷查詢結果集&#xff0c;特別適用于處理大量數據時。 一、游標的定義與作用 定義&#xff1a; 游標是一種能從數據記錄的結果集中每次提取一條記錄的機制。在MongoDB中&#xff0c;游…

【從零開始學習計算機科學】編譯原理(七)運行時刻環境

【從零開始學習計算機科學】編譯原理(七)運行時刻環境 運行時刻環境存儲組織空間的棧式分配活動樹活動記錄和控制棧簡單棧式存貯分配C語言的過程調用和過程返回時的存貯管理堆式存儲分配堆式存儲分配的功能垃圾回收基于跟蹤的垃圾回收短停頓垃圾回收運行時刻環境 存儲組織 …

2025-03-08 學習記錄--C/C++-PTA 習題10-1 判斷滿足條件的三位數

合抱之木&#xff0c;生于毫末&#xff1b;九層之臺&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、題目描述 ?? 裁判測試程序樣例&#xff1a; #include <stdio.h> #include <math.h>int search( int n );int…

【ArcGIS】地理坐標系

文章目錄 一、坐標系理論體系深度解析1.1 地球形態的數學表達演進史1.1.1 地球曲率的認知變化1.1.2 參考橢球體參數對比表 1.2 地理坐標系的三維密碼1.2.1 經緯度的本質1.2.2 大地基準面&#xff08;Datum&#xff09;的奧秘 1.3 投影坐標系&#xff1a;平面世界的誕生1.3.1 投…

DeepSeek刷力扣輔助題單 存留記錄

最近感覺被什么東西阻擋了腳步,經大佬建議,做算法題提升一下思維 首先,我不認為算法題要死磕,因為我沒有那個天賦,但是我還是要嘴硬一下 其次,我沒有計算機基礎的學習背景,因為我是修飛機專升本來的自動化專業,24年七月幾乎零基礎學習Unity 和 C#,努力學習到現在感覺已經盡力了…

化工廠防爆氣象站:為石油化工、天然氣等領域提供安全保障

【TH-FB02】在石油化工、天然氣等高危行業中&#xff0c;安全生產是至關重要的。這些行業常常面臨著易燃易爆、有毒有害等潛在風險&#xff0c;因此&#xff0c;對氣象條件的監測和預警顯得尤為重要。化工廠防爆氣象站作為一種專門設計用于這些特殊環境的氣象監測設備&#xff…

《MySQL數據庫從零搭建到高效管理|庫的基本操作》

目錄 一、數據庫的操作 1.1 展示數據庫 1.2 創建數據庫 1.3 使用數據庫 1.4 查看當前數據庫 1.5 刪除數據庫 1.6 小結 二、常用數據類型 2.1 數值類型 2.2 字符串類型 2.3 日期類型 一、數據庫的操作 打開MySQL命令行客戶端&#xff0c;安裝完MySQL后會有兩個客戶端…

計算機考研C語言

C語言程序設計從入門到精通【2025完整版】考研復試 嵌入式 計算機二級 軟考 專升本也適用_嗶哩嗶哩_bilibili 1、第一個C程序 helloC #include <stdio.h>int main(){printf("hehe");return 0;}每個C語言程序不管有多少行代碼&#xff0c;都是從main函數開始執…

力扣hot100二刷——鏈表

第二次刷題不在idea寫代碼&#xff0c;而是直接在leetcode網站上寫&#xff0c;“逼”自己掌握常用的函數。 標志掌握程度解釋辦法?Fully 完全掌握看到題目就有思路&#xff0c;編程也很流利??Basically 基本掌握需要稍作思考&#xff0c;或者看到提示方法后能解答???Sl…

Word 小黑第2套

對應大貓42 Word1 從文件中導入新樣式 樣式組 -管理樣式 -導入導出 -關閉Normal文件 -打開文件 -修改文件 -選中所需 -復制 調整字符寬度 調整字符間距 -字體組 加寬 適當修改磅值 文字效果通過文字組修改 另起一頁&#xff0c;分隔符&#xff08;布局 -分隔符 -分節符 -下一…

iTextSharp-PDF批量導出

HTML轉PDF批量導出速度太慢且使用Spire.pdf.dll限制頁簽10后需要開通會員才能使用-做出優化 環境&#xff1a;U9 - UI插件 需求&#xff1a;選擇需要導出的客戶查詢對應對賬數據批量導出PDF并彈出下載框保存到默認位置 using System; using System.Collections.Generic; us…

【RabbitMQ】Spring Boot 結合 RabbitMQ 完成應用間的通信

&#x1f525;個人主頁&#xff1a; 中草藥 &#x1f525;專欄&#xff1a;【中間件】企業級中間件剖析 Spring 框架與 RabbitMQ 的整合主要通過 Spring AMQP&#xff08;Advanced Message Queuing Protocol&#xff09;模塊實現&#xff0c;提供了便捷的消息隊列開發能力。 引…

CDefView::_GetPIDL函數分析之ListView_GetItem函數的參數item的item.mask 為LVIF_PARAM

CDefView::_GetPIDL函數分析之ListView_GetItem函數的參數item的item.mask 為LVIF_PARAM 第一部分&#xff1a; 1: kd> t SHELL32!CDefView::_GetPIDL: 001b:77308013 55 push ebp 1: kd> dv this 0x00000015 i 0n21 …