MyBatis中mapper.xml 的sql映射規則

一、SQL 映射文件核心元素

MyBatis 映射文件的頂級元素(按定義順序):

  1. cache:命名空間的緩存配置。
  2. cache-ref:引用其他命名空間的緩存。
  3. resultMap:自定義結果集映射。
  4. sql:可重用的 SQL 片段。
  5. insertupdatedelete:數據操作語句。
  6. select:查詢語句。

二、參數傳遞與處理

1. 單參數

-基礎類型/字符串

<select id="selectUser" resultType="User" parameterType="int">SELECT * FROM user WHERE id = #{id}
</select>

-POJO 對象

<insert id="insertUser" parameterType="User">INSERT INTO user (name, email) VALUES (#{name}, #{email})
</insert>

2. 多參數

- 默認 param1, param2(不推薦):

<select id="selectUser" resultType="User">SELECT * FROM user WHERE id = #{param1} AND name = #{param2}
</select>

- @Param 注解(推薦):

User selectUser(@Param("id") int id, @Param("name") String name);
<select id="selectUser" resultType="User">SELECT * FROM user WHERE id = #{id} AND name = #{name}
</select>

3. 復雜參數

- Map 類型

<select id="selectUserByMap" resultType="User" parameterType="map">SELECT * FROM user WHERE name = #{name} AND age = #{age}
</select>

- 混合參數(POJO + @Param):

List<User> selectUsers(@Param("role") String role, User user);
<select id="selectUsers" resultType="User">SELECT * FROM user WHERE role = #{role} AND age = #{user.age}
</select>

三、主鍵生成與回填

1. 自增主鍵(如 MySQL)

<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">INSERT INTO user (name, email) VALUES (#{name}, #{email})
</insert>
  • useGeneratedKeys="true":啟用 JDBC 的自動生成主鍵。
  • keyProperty="id":將生成的主鍵賦值給對象的 id 屬性。

2. 非自增主鍵(如 Oracle)

<insert id="insertUser"><selectKey keyProperty="id" resultType="int" order="BEFORE">SELECT MAX(id) + 1 FROM user</selectKey>INSERT INTO user (id, name) VALUES (#{id}, #{name})
</insert>
  • order="BEFORE":先執行 selectKey 生成主鍵,再插入數據。

四、結果映射(resultMap

1. 基礎映射

<resultMap id="userResultMap" type="User"><id property="id" column="user_id" /><result property="name" column="user_name" />
</resultMap>

2. 關聯對象(一對一)

<resultMap id="userWithRoleMap" type="User"><association property="role" javaType="Role"><id property="roleId" column="role_id" /><result property="roleName" column="role_name" /></association>
</resultMap>

3. 集合映射(一對多)

<resultMap id="userWithOrdersMap" type="User"><collection property="orders" ofType="Order"><id property="orderId" column="order_id" /><result property="orderNo" column="order_no" /></collection>
</resultMap>

五、動態 SQL

1. 條件查詢(<if> + <where>

<select id="selectUser" resultType="User">SELECT * FROM user<where><if test="name != null">AND name = #{name}</if><if test="age != null">AND age = #{age}</if></where>
</select>

2. 循環遍歷(<foreach>

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

1. 參數是 List

當方法參數直接傳遞一個 List 時,MyBatis 默認將其封裝為 Map,鍵為 list

示例代碼:
// DAO 方法
List<User> selectUsersByIds(@Param("ids") List<Integer> ids);
<!-- XML 映射 -->
<select id="selectUsersByIds" resultType="User">SELECT * FROM user WHERE id IN<foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach>
</select>
關鍵點:
  • collection="ids":對應 @Param("ids") 注解的參數名。
  • item="id":遍歷的每個元素變量名。
  • open="("close=")":包裹生成的 SQL 片段。
  • separator=",":元素之間的分隔符。

2. 參數是 Set

Set 的處理方式與 List 類似,MyBatis 會自動將其轉換為 List 處理。

示例代碼:
// DAO 方法
List<User> selectUsersByNames(@Param("names") Set<String> names);
<!-- XML 映射 -->
<select id="selectUsersByNames" resultType="User">SELECT * FROM user WHERE name IN<foreach collection="names" item="name" open="(" separator="," close=")">#{name}</foreach>
</select>

3. 參數是數組

當直接傳遞數組時,collection 屬性需指定為 array

示例代碼:
// DAO 方法
List<User> selectUsersByIds(int[] ids);
<!-- XML 映射 -->
<select id="selectUsersByIds" resultType="User">SELECT * FROM user WHERE id IN<foreach collection="array" item="id" open="(" separator="," close=")">#{id}</foreach>
</select>

4. 參數是 Map 中的集合

如果參數是 Map,需通過 @Param 指定鍵名。

示例代碼:
// DAO 方法
List<User> selectUsers(@Param("data") Map<String, Object> data);
<!-- XML 映射 -->
<select id="selectUsers" resultType="User">SELECT * FROM user WHERE id IN<foreach collection="data.ids" item="id" open="(" separator="," close=")">#{id}</foreach>AND name IN<foreach collection="data.names" item="name" open="(" separator="," close=")">#{name}</foreach>
</select>

5. 批量插入示例

使用 <foreach> 實現批量插入:

// DAO 方法
void batchInsertUsers(@Param("users") List<User> users);
<!-- XML 映射 -->
<insert id="batchInsertUsers">INSERT INTO user (name, email) VALUES<foreach collection="users" item="user" separator=",">(#{user.name}, #{user.email})</foreach>
</insert>

6. 遍歷 Map 類型

當集合元素是 Map 時,indexitem 分別代表鍵和值。

示例代碼:
// DAO 方法
void insertUserRoles(@Param("roles") Map<Integer, String> roles);
<!-- XML 映射 -->
<insert id="insertUserRoles">INSERT INTO role (user_id, role_name) VALUES<foreach collection="roles" index="userId" item="roleName" separator=",">(#{userId}, #{roleName})</foreach>
</insert>

7.關鍵注意事項

  1. 參數類型匹配

    • 單參數集合需通過 @Param 顯式命名。
    • 多參數需用 @Param 避免混淆。
  2. 安全與性能

    • 始終使用 #{} 占位符(防止 SQL 注入)。
    • 批量操作時,注意數據庫的 SQL 語句長度限制。
  3. 動態 SQL 靈活性

    • 結合 <if> 標簽實現條件遍歷:
      <foreach collection="ids" item="id"><if test="id != null">#{id}</if>
      </foreach>
      

8.總結

參數類型collection示例場景
List@Param 指定的名稱IN 查詢、批量插入
Set@Param 指定的名稱去重后的 IN 查詢
數組array原生數組參數的 IN 查詢
Mapmap.key@Param復雜參數組合的動態查詢

通過合理使用 <foreach>,可以高效處理集合類參數,簡化批量操作和動態 SQL 的編寫。

3. 分支選擇(<choose>

<select id="selectUserByChoose" resultType="User">SELECT * FROM user<where><choose><when test="id != null">id = #{id}</when><otherwise>status = 1</otherwise></choose></where>
</select>

六、高級特性

1. 分步查詢與延遲加載

  • 分步查詢
    <resultMap id="catMap" type="Cat"><association property="owner" select="selectOwnerById" column="owner_id" />
    </resultMap>
    
  • 延遲加載配置
    <settings><setting name="lazyLoadingEnabled" value="true" /><setting name="aggressiveLazyLoading" value="false" />
    </settings>
    

2. SQL 片段復用(<sql>

<sql id="userColumns">id, name, email</sql>
<select id="selectUser" resultType="User">SELECT <include refid="userColumns" /> FROM user
</select>

七、特殊處理

1. #{}${}

以下是 #{}${} 的核心區別及使用場景總結,結合動態表名/字段的示例說明:


1. #{}${} 的核心區別

特性#{}${}
原理預編譯(PreparedStatement)字符串直接拼接(SQL 注入風險)
安全性防 SQL 注入(推薦)不安全(需嚴格校驗輸入)
適用場景參數值(如 WHERE 條件)動態表名、列名、排序字段等
示例WHERE id = #{id}ORDER BY ${columnName}

2. 動態表名與字段的示例

場景 1:動態表名(如多租戶系統)
<!-- 根據傳入的表名查詢數據 -->
<select id="selectByDynamicTable" resultType="User">SELECT * FROM ${tableName} WHERE id = #{id}
</select>
  • 調用方式
    List<User> users = userDao.selectByDynamicTable("user_2023", 1001);
    
  • 生成 SQL
    SELECT * FROM user_2023 WHERE id = ?
    
場景 2:動態排序字段
<!-- 根據傳入的排序字段動態排序 -->
<select id="selectUsersOrderBy" resultType="User">SELECT * FROM user ORDER BY ${orderByColumn} ${sortDirection}
</select>
  • 調用方式
    List<User> users = userDao.selectUsersOrderBy("age", "DESC");
    
  • 生成 SQL
    SELECT * FROM user ORDER BY age DESC
    
場景 3:動態列名(如選擇特定字段)
<!-- 選擇動態列 -->
<select id="selectDynamicColumns" resultType="map">SELECT ${columns} FROM user WHERE id = #{id}
</select>
  • 調用方式
    Map<String, Object> result = userDao.selectDynamicColumns("name, email", 1001);
    
  • 生成 SQL
    SELECT name, email FROM user WHERE id = ?
    

3. 安全注意事項

  • 風險場景:如果用戶輸入未經校驗,直接使用 ${} 可能導致 SQL 注入。

    // 危險示例:用戶輸入惡意表名
    String tableName = "user; DROP TABLE user; --";
    userDao.selectByDynamicTable(tableName, 1001); 
    

    生成 SQL

    SELECT * FROM user; DROP TABLE user; -- WHERE id = ?
    
  • 防御措施

    1. 白名單校驗:限制動態值的范圍。
      // 只允許特定表名
      if (!Arrays.asList("user", "employee").contains(tableName)) {throw new IllegalArgumentException("非法表名");
      }
      
    2. 轉義特殊字符:過濾或轉義輸入中的特殊符號(如 ', ;)。

4. 總結

場景占位符示例安全性
參數值(如 id#{}WHERE id = #{id}安全(推薦)
動態表名${}FROM ${tableName}需校驗輸入(風險)
動態列名/排序字段${}ORDER BY ${column}需校驗輸入(風險)

原則

  • 優先使用 #{},確保安全性。
  • 僅在必要時使用 ${},并嚴格校驗輸入值。

2. 返回類型

1. 單對象:resultType="User"

  • 作用:將單條數據庫記錄映射到一個 Java 對象(如 User)。
  • 規則
    • 數據庫列名需與 Java 對象屬性名一致(或通過別名匹配),否則需使用 resultMap
    • 若查詢結果為多條記錄,會拋出異常(TooManyResultsException)。
  • 示例
    <select id="selectUserById" resultType="User">SELECT * FROM user WHERE id = #{id}
    </select>
    
    • 返回類型:User 對象。
    • 若未查詢到數據,返回 null

2. 集合:resultType="User"

  • 作用:將多條數據庫記錄映射為 List<User>
  • 規則
    • MyBatis 自動將多行結果封裝為 List,無需額外配置。
    • 若查詢結果為空,返回空列表(非 null)。
  • 示例
    <select id="selectAllUsers" resultType="User">SELECT * FROM user
    </select>
    
    • 返回類型:List<User>
    • 即使結果為空,返回 Collections.emptyList()

3. Map 類型

3.1 直接返回 MapresultType="map"
  • 作用:將單條記錄映射為 Map<String, Object>,鍵為列名,值為對應數據。
  • 示例
    <select id="selectUserAsMap" resultType="map">SELECT id, name FROM user WHERE id = #{id}
    </select>
    
    • 返回類型:Map<String, Object>,如 {"id": 1, "name": "Alice"}
3.2 使用 @MapKey 注解返回 Map<K, V>
  • 作用:將多條記錄映射為 Map<K, V>,其中:
    • 鍵(K):由 @MapKey 指定的屬性值(如 id)。
    • 值(V):對應的 Java 對象。
  • 規則
    • 需在 DAO 接口方法上添加 @MapKey("屬性名")
    • 查詢結果中指定的屬性值必須唯一,否則會覆蓋或拋出異常。
  • 示例
    @MapKey("id")
    Map<Integer, User> selectAllUsersAsMap();
    
    <select id="selectAllUsersAsMap" resultType="User">SELECT * FROM user
    </select>
    
    • 返回類型:Map<Integer, User>,鍵為 Userid,值為對應的 User 對象。

4.關鍵區別與注意事項

類型resultType返回值類型適用場景
單對象UserUser查詢單條記錄
集合UserList<User>查詢多條記錄
單條記錄的 MapmapMap<String, Object>需要靈活訪問列名/值的場景
多條記錄的 MapUser + @MapKeyMap<K, User>以特定屬性為鍵,對象為值的映射

5.常見問題

  1. 字段名與屬性名不一致

    • 使用 resultMap 或 SQL 別名(AS)解決:
      <select id="selectUser" resultType="User">SELECT user_id AS id, user_name AS name FROM user
      </select>
      
  2. 集合返回類型為 null

    • MyBatis 默認返回空集合(Collections.emptyList()),而非 null
  3. @MapKey 的唯一性

    • 若指定的鍵屬性(如 id)存在重復值,MyBatis 會保留最后一個匹配的對象,可能導致數據丟失。

6.總結

  • 單對象:直接使用 resultType="User"
  • 集合:同樣使用 resultType="User",MyBatis 自動封裝為 List
  • Map
    • 單條記錄:resultType="map"
    • 多條記錄:結合 @MapKey 注解,指定鍵屬性。

合理選擇 resultType 可簡化結果映射,提升開發效率。


八、總結

場景解決方案示例
自增主鍵useGeneratedKeys="true" + keyProperty="id"插入后自動填充 id
多參數查詢@Param 注解#{id} + #{name}
字段名與屬性名映射resultMap<result property="userName" column="user_name" />
動態條件查詢<if> + <where>按條件拼接 WHERE 子句
批量操作<foreach>IN (1, 2, 3)

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

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

相關文章

【計算機網絡】計算機網絡協議、接口與服務全面解析——結合生活化案例與圖文詳解

協議、接口與服務 導讀一、協議1.1 定義1.2 組成 二、接口三、服務3.1 定義3.2 服務與協議的區別3.3 分類3.3.1 面向連接服務于無連接服務3.3.2 可靠服務和不可靠服務3.3.3 有應答服務和無應答服務 結語 導讀 大家好&#xff0c;很高興又和大家見面啦&#xff01;&#xff01;…

Ubuntu服務器中Swapper如何與虛擬內存配合

在Ubuntu服務器中&#xff0c;Swapper和虛擬內存是操作系統中重要的概念&#xff0c;它們共同協作以提高系統的內存管理效率。當物理內存不足時&#xff0c;Swapper會幫助系統將不活躍的數據從內存轉移到磁盤上的交換空間(Swap)&#xff0c;以釋放內存給需要更多資源的進程。下…

SQL Server 中常見的數據類型及其詳細解釋、內存占用和適用場景

以下是 SQL Server 中常見的數據類型及其詳細解釋、內存占用和適用場景&#xff1a; 數據類型類別數據類型解釋內存占用適用場景整數類型bigint用于存儲范圍較大的整數&#xff0c;范圍是 -2^63 (-9,223,372,036,854,775,808) 到 2^63-1 (9,223,372,036,854,775,807)8 字節需要…

vue數字公式篇 Tinymce結合使用(二)

繼上一篇的數字公式 &#xff0c; 這次的功能是將公式能插入編輯器以及修改 1、Tinymce 自定義 LateX 按鈕&#xff0c;打開公式編輯器窗口 LateX.vue window.tinymce.init({...//基礎配置這里我就不寫了setup(ed) {//自定義 LateX 按鈕ed.ui.registry.addButton(LateX, {text:…

python數據增強和轉換

數據增強和轉換 固定轉換隨機轉換概率控制的轉換 固定轉換 邊緣補充像素(Pad)尺寸變換(Resize)中心截取(CenterCrop)頂角及中心截取(FiveCrop)尺灰度變換(GrayScale) 概率控制的轉換 隨機垂直翻轉(RandomVerticalFlip)隨機應用(RandomApply) # -*- coding: utf-8 -*- fro…

Ubuntu下UEFI安全啟動安裝Nvdia驅動

簡介 眾所周知&#xff0c;Ubuntu默認使用Nouveau開源驅動&#xff0c;其性能受限&#xff0c;因此我們需要安裝Nvidia專用驅動。 安裝專用驅動的一般方法非常簡單&#xff0c;只需要sudo ubuntu-drivers devices && sudo ubuntu-drivers autoinstall即可&#xff0c…

05_循環結構三目運算符

目錄 一、雙重for循環 練習 二、break關鍵字 三、continue 關鍵字 練習 四、三元運算 / 三目運算 一、雙重for循環 外層循環 循環一次&#xff0c;&#xff0c;&#xff0c;內層循環 循環一圈&#xff01;&#xff01;&#xff01; 循環里嵌套循環&#xff1a; for(var…

數據結構初階-二叉樹鏈式

目錄 1.概念與結構 2.二叉數鏈式的實現 2.1遍歷規則 2.2申請內存空間 2.3手動構建一棵二叉樹 2.4二叉樹結點的個數 2.5二叉樹葉子結點的個數 2.6二叉樹第K層結點個數 2.7二叉樹的高度 2.8二叉樹中查找值為x的結點 2.9二叉樹的銷毀 3.層序遍歷 3.1概念 3.2層序遍歷…

鴻蒙HarmonyOS NEXT之無感監聽

鴻蒙中存在一些無感監聽&#xff0c;這些監聽經過系統API封裝使用很簡單&#xff0c;但是對實際業務開發中有很重要&#xff0c;例如埋點業務、數據統計、行為上報、切面攔截等。 Navigation的頁面切換 在鴻蒙中Navigation被用來作為路由棧進行頁面跳轉&#xff0c;如果你想知…

批量處理word里面表格的空白行

1&#xff0c;隨便打開一個word文檔。 2&#xff0c;按下Alt F11 VBA編輯器,在左側的「工程資源管理器」窗口中找到Normal 項目,右鍵選擇插入->模塊。 彈出一下彈窗 3&#xff0c;輸入一下代碼 代碼&#xff1a; Sub RemoveEmptyTableRows()Dim tbl As TableDim row As R…

3ds Max 2026 新功能全面解析

一、視口性能與交互體驗升級 1. Hydra 2.0 視口渲染引擎 3ds Max 2026 引入了 Hydra 2.0&#xff0c;大幅優化了視口渲染性能&#xff0c;尤其是在處理復雜場景和高質量實時預覽時&#xff0c;流暢度提升顯著。 支持USD&#xff08;通用場景描述&#xff09;格式&#xff0c…

JVM垃圾回收筆記02-垃圾回收器

文章目錄 前言1.串行(Serial 收集器/Serial Old 收集器)Serial 收集器Serial Old 收集器相關參數-XX:UseSerialGC 2.吞吐量優先(Parallel Scavenge 收集器/Parallel Old 收集器)Parallel Scavenge 收集器Parallel Old 收集器相關參數-XX:UseParallelGC ~ -XX:UseParallelOldGC-…

圖解AUTOSAR_SWS_UDPNetworkManagement

AUTOSAR UDP 網絡管理 (UdpNm) 技術詳解 基于 AUTOSAR 規范的 UDP 網絡管理模塊可視化指南 目錄 AUTOSAR UDP 網絡管理 (UdpNm) 技術詳解 目錄1. 概述2. UdpNm 狀態機 2.1 狀態機概述2.2 主要狀態說明2.3 狀態轉換機制2.4 并行狀態3. UdpNm 架構設計 3.1 架構概述3.2 接口設計3…

android 圖形開發的技能學習路線

需要以下幾個方面的知識&#xff1a; OpenGL ES的基礎和高級應用圖形渲染管線的工作原理3D數學&#xff08;矩陣、向量、四元數&#xff09;著色器編程&#xff08;GLSL&#xff09;libGDX框架的使用和定制性能優化和內存管理跨平臺渲染技術 接下來&#xff0c;考慮如何結構化…

使用AI一步一步實現若依(26)

功能26&#xff1a;新增一個新員工培訓頁面 功能25&#xff1a;角色管理 功能24&#xff1a;菜單管理 功能23&#xff1a;從后端獲取路由/菜單數據 功能22&#xff1a;用戶管理 功能21&#xff1a;使用axios發送請求 功能20&#xff1a;使用分頁插件 功能19&#xff1a;集成My…

vue響應式原理剖析

一、什么是響應式? 我們先來看一下響應式意味著什么?我們來看一段代碼: m有一個初始化的值,有一段代碼使用了這個值; 那么在m有一個新的值時,這段代碼可以自動重新執行; let m = 20 console.log(m) console.log(m * 2)m = 40上面的這樣一種可以自動響應數據變量的代碼機…

無人機航電系統電池技術解析!

1. 常用電池類型 鋰聚合物電池&#xff08;LiPo&#xff09; 特點&#xff1a;高能量密度、輕量化、放電效率高&#xff0c;是目前主流選擇。 缺點&#xff1a;對過充/過放敏感&#xff0c;需嚴格管理&#xff0c;存在輕微膨脹或起火風險。 鋰離子電池&#xff08;Li-ion…

ubuntu下終端打不開的排查思路和解決方法

問題現象描述&#xff1a;ubuntu開機后系統桌面顯示正常&#xff0c;其他圖形化的app也都能打開無異常&#xff0c;唯獨只有terminal終端打不開&#xff0c;無論是鼠標點擊終端軟件&#xff0c;還是ctrlaltt&#xff0c;還是altF2后輸入gnome-terminal后按回車&#xff0c;這三…

Maven入門

1、簡介 Apache Maven是一個項目管理及自動構建工具&#xff0c;由Apache軟件基金會所提供。基于項目對象模型&#xff08;縮寫&#xff1a;POM&#xff09;概念&#xff0c;Maven利用一個中央信息片斷能管理一個項目的構建、報告和文檔等步驟。 2、作用 1&#xff09;依賴導…

Rk3588,Opencv讀取Gmsl相機,Rga yuv422轉換rgb (降低CPU使用率)

RK3588, 使用OpenCv 讀取 gmsl 相機,獲得yuv422格式圖像, 使用 rga 轉換 rgb 圖像。減少cpu占用率. 查看相機信息 v4l2-ctl --all -d /dev/cam0 , 查看自己相機分辨率,輸出格式等信息,對應修改后續代碼測試… Driver Info:Driver name : rkcifCard type : rkc…