最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MyBatis的關聯(lián)查詢實現(xiàn)(一對一、一對多、多對多)

 更新時間:2025年12月11日 10:38:22   作者:AA-代碼批發(fā)V哥  
本文主要介紹了MyBatis的關聯(lián)查詢實現(xiàn),包括一對一、一對多和多對多關系的實現(xiàn)方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

實際開發(fā)中數(shù)據(jù)庫表之間往往存在關聯(lián)關系(如用戶與訂單、訂單與商品),MyBatis的關聯(lián)查詢用于處理這些關系,將多表數(shù)據(jù)映射為Java對象的關聯(lián)關系,相比JDBC手動處理結(jié)果集拼接,MyBatis通過resultMapassociationcollection標簽,能自動完成關聯(lián)數(shù)據(jù)的映射。本文我將系統(tǒng)講解MyBatis關聯(lián)查詢的核心實現(xiàn),包括一對一、一對多、多對多關系,并結(jié)合實例解析查詢方式與優(yōu)化技巧。

一、關聯(lián)查詢的基本概念

1.1 數(shù)據(jù)庫表關聯(lián)關系

數(shù)據(jù)庫表的關聯(lián)關系主要有三種:

  • 一對一:A表一條記錄對應B表一條記錄(如用戶與身份證,一個用戶對應一個身份證);
  • 一對多:A表一條記錄對應B表多條記錄(如用戶與訂單,一個用戶可有多筆訂單);
  • 多對多:A表多條記錄對應B表多條記錄(如學生與課程,一個學生可選多門課程,一門課程可有多個學生),通常通過中間表實現(xiàn)。

1.2 MyBatis關聯(lián)查詢的核心

MyBatis通過resultMap實現(xiàn)關聯(lián)查詢,核心標簽:

  • association:映射一對一關系(如用戶對象中包含一個身份證對象);
  • collection:映射一對多多對多關系(如用戶對象中包含一個訂單列表)。

關聯(lián)查詢有兩種實現(xiàn)方式:

  • 嵌套查詢:先查詢主表數(shù)據(jù),再根據(jù)主表字段查詢關聯(lián)表(多輪查詢);
  • 連接查詢:通過JOIN語句一次性查詢多表數(shù)據(jù)(單輪查詢)。

后續(xù)將通過案例詳細對比這兩種方式的優(yōu)缺點。

二、一對一關聯(lián)查詢

以“用戶(user)與身份證(id_card)”為例,一個用戶對應一個身份證,實現(xiàn)一對一關聯(lián)查詢。

2.1 數(shù)據(jù)庫表設計

-- 用戶表
CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL,
  `age` int DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 身份證表(與用戶一對一關聯(lián))
CREATE TABLE `id_card` (
  `id` int NOT NULL AUTO_INCREMENT,
  `card_no` varchar(20) NOT NULL, -- 身份證號
  `user_id` int NOT NULL, -- 關聯(lián)用戶ID(外鍵)
  PRIMARY KEY (`id`),
  UNIQUE KEY `user_id` (`user_id`) -- 一對一:user_id唯一
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

2.2 實體類設計

// 用戶類(包含一個身份證對象)
@Data
public class User {
    private Integer id;
    private String username;
    private Integer age;
    // 一對一關聯(lián):用戶包含一個身份證
    private IdCard idCard; 
}

// 身份證類
@Data
public class IdCard {
    private Integer id;
    private String cardNo;
    private Integer userId;
}

2.3 一對一查詢實現(xiàn)

2.3.1 方式1:連接查詢(推薦)

通過JOIN語句一次性查詢用戶和身份證數(shù)據(jù),再通過association映射關聯(lián)對象。

Mapper接口

// 根據(jù)用戶ID查詢用戶及關聯(lián)的身份證
User selectUserWithIdCardById(Integer id);

Mapper XML

<!-- 定義resultMap:映射用戶及身份證 -->
<resultMap id="UserWithIdCardMap" type="User">
    <!-- 用戶表字段映射 -->
    <id column="id" property="id"/>
    <result column="username" property="username"/>
    <result column="age" property="age"/>
    
    <!-- 一對一關聯(lián):association映射IdCard對象 -->
    <association property="idCard" javaType="IdCard">
        <id column="card_id" property="id"/> <!-- 注意:避免與user.id字段沖突 -->
        <result column="card_no" property="cardNo"/>
        <result column="user_id" property="userId"/>
    </association>
</resultMap>

<!-- 連接查詢:一次性查詢用戶和身份證 -->
<select id="selectUserWithIdCardById" resultMap="UserWithIdCardMap">
    SELECT 
        u.id, u.username, u.age,
        ic.id AS card_id, ic.card_no, ic.user_id
    FROM user u
    LEFT JOIN id_card ic ON u.id = ic.user_id
    WHERE u.id = #{id}
</select>

核心說明

  • associationproperty:對應User類中的idCard屬性;
  • javaType:指定關聯(lián)對象的類型(IdCard);
  • 表連接時需通過AS為關聯(lián)表字段起別名(如ic.id AS card_id),避免與主表字段(u.id)沖突。

2.3.2 方式2:嵌套查詢

先查詢用戶數(shù)據(jù),再通過用戶ID查詢身份證(分兩次查詢)。

步驟1:查詢身份證的Mapper

// IdCardMapper接口
IdCard selectById(Integer id);
<select id="selectById" resultType="IdCard">
    SELECT id, card_no, user_id FROM id_card WHERE id = #{id}
</select>

步驟2:查詢用戶并嵌套查詢身份證

<resultMap id="UserWithIdCardNestedMap" type="User">
    <id column="id" property="id"/>
    <result column="username" property="username"/>
    <result column="age" property="age"/>
    
    <!-- 嵌套查詢:通過select屬性指定查詢關聯(lián)對象的方法 -->
    <association 
        property="idCard" 
        javaType="IdCard"
        column="id" <!-- 將用戶id作為參數(shù)傳遞給關聯(lián)查詢 -->
        select="com.example.mapper.IdCardMapper.selectByUserId"/> <!-- 關聯(lián)查詢的Mapper方法 -->
</resultMap>

<select id="selectUserWithIdCardNestedById" resultMap="UserWithIdCardNestedMap">
    SELECT id, username, age FROM user WHERE id = #{id}
</select>

核心說明

  • associationselect:指定查詢關聯(lián)對象的Mapper方法(全類名+方法名);
  • column:將主查詢的id(用戶ID)作為參數(shù)傳遞給selectByUserId方法。

2.3.3 兩種方式對比

方式優(yōu)點缺點適用場景
連接查詢單輪查詢,性能好SQL較復雜(多表JOIN)關聯(lián)數(shù)據(jù)必須查詢,且表數(shù)據(jù)量不大
嵌套查詢SQL簡單,邏輯清晰多輪查詢(N+1問題),性能較差關聯(lián)數(shù)據(jù)可選查詢(按需加載)

三、一對多關聯(lián)查詢

以“用戶(user)與訂單(order)”為例,一個用戶可有多筆訂單,實現(xiàn)一對多關聯(lián)查詢。

3.1 數(shù)據(jù)庫表設計

-- 訂單表(與用戶一對多關聯(lián))
CREATE TABLE `order` (
  `id` int NOT NULL AUTO_INCREMENT,
  `order_no` varchar(20) NOT NULL, -- 訂單號
  `total_amount` decimal(10,2) NOT NULL, -- 總金額
  `user_id` int NOT NULL, -- 關聯(lián)用戶ID
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

3.2 實體類設計

// 用戶類(包含訂單列表)
@Data
public class User {
    private Integer id;
    private String username;
    private Integer age;
    // 一對多關聯(lián):用戶包含多個訂單
    private List<Order> orders; 
}

// 訂單類
@Data
public class Order {
    private Integer id;
    private String orderNo;
    private BigDecimal totalAmount;
    private Integer userId;
}

3.3 一對多查詢實現(xiàn)

連接查詢為例(推薦,單輪查詢性能更好):

Mapper接口

// 查詢用戶及關聯(lián)的所有訂單
User selectUserWithOrdersById(Integer id);

Mapper XML

<!-- 定義resultMap:映射用戶及訂單列表 -->
<resultMap id="UserWithOrdersMap" type="User">
    <!-- 用戶表字段 -->
    <id column="id" property="id"/>
    <result column="username" property="username"/>
    <result column="age" property="age"/>
    
    <!-- 一對多關聯(lián):collection映射訂單列表 -->
    <collection property="orders" ofType="Order"> <!-- ofType指定集合元素類型 -->
        <id column="order_id" property="id"/> <!-- 訂單ID(別名避免沖突) -->
        <result column="order_no" property="orderNo"/>
        <result column="total_amount" property="totalAmount"/>
        <result column="user_id" property="userId"/>
    </collection>
</resultMap>

<!-- 連接查詢:用戶與訂單 -->
<select id="selectUserWithOrdersById" resultMap="UserWithOrdersMap">
    SELECT 
        u.id, u.username, u.age,
        o.id AS order_id, o.order_no, o.total_amount, o.user_id
    FROM user u
    LEFT JOIN `order` o ON u.id = o.user_id
    WHERE u.id = #{id}
</select>

核心說明

  • collectionproperty:對應User類中的orders屬性(List類型);
  • ofType:指定集合中元素的類型(Order),區(qū)別于javaType(用于指定屬性類型,如List);
  • 主表與關聯(lián)表的字段需通過別名區(qū)分(如o.id AS order_id),避免映射混亂。

四、多對多關聯(lián)查詢

以“學生(student)與課程(course)”為例,一個學生可選多門課程,一門課程可有多個學生,通過中間表student_course實現(xiàn)關聯(lián)。

4.1 數(shù)據(jù)庫表設計

-- 學生表
CREATE TABLE `student` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 課程表
CREATE TABLE `course` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 中間表(多對多關聯(lián))
CREATE TABLE `student_course` (
  `id` int NOT NULL AUTO_INCREMENT,
  `student_id` int NOT NULL,
  `course_id` int NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_stu_course` (`student_id`,`course_id`) -- 避免重復關聯(lián)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

4.2 實體類設計

// 學生類(包含課程列表)
@Data
public class Student {
    private Integer id;
    private String name;
    // 多對多關聯(lián):學生包含多個課程
    private List<Course> courses;
}

// 課程類
@Data
public class Course {
    private Integer id;
    private String name;
}

4.3 多對多查詢實現(xiàn)

多對多查詢本質(zhì)是一對多的擴展(通過中間表連接),以連接查詢?yōu)槔?/p>

Mapper接口

// 查詢學生及所選課程
Student selectStudentWithCoursesById(Integer id);

Mapper XML

<resultMap id="StudentWithCoursesMap" type="Student">
    <id column="id" property="id"/>
    <result column="name" property="name"/>
    
    <!-- 多對多:collection映射課程列表 -->
    <collection property="courses" ofType="Course">
        <id column="course_id" property="id"/>
        <result column="course_name" property="name"/>
    </collection>
</resultMap>

<select id="selectStudentWithCoursesById" resultMap="StudentWithCoursesMap">
    SELECT 
        s.id, s.name,
        c.id AS course_id, c.name AS course_name
    FROM student s
    LEFT JOIN student_course sc ON s.id = sc.student_id
    LEFT JOIN course c ON sc.course_id = c.id
    WHERE s.id = #{id}
</select>

核心說明

  • 多對多通過“主表→中間表→關聯(lián)表”的JOIN實現(xiàn);
  • collection標簽用法與一對多相同(均映射集合),區(qū)別在于表連接邏輯。

五、關聯(lián)查詢的優(yōu)化與最佳實踐

5.1 避免N+1查詢問題

N+1問題:嵌套查詢時,若查詢N個主表記錄,會觸發(fā)1次主表查詢+N次關聯(lián)表查詢,導致性能下降。

示例:查詢所有用戶及其訂單(嵌套查詢方式):

<!-- 1次主表查詢:查詢所有用戶 -->
<select id="selectAllUser" resultMap="UserWithOrdersNestedMap">
    SELECT id, username, age FROM user
</select>

<!-- 每個用戶觸發(fā)1次訂單查詢(若有100個用戶,觸發(fā)100次) -->
<collection property="orders" select="selectOrdersByUserId" column="id"/>

解決方案

  • 優(yōu)先使用連接查詢(單輪查詢,無N+1問題);
  • 若需嵌套查詢,開啟MyBatis二級緩存,緩存關聯(lián)查詢結(jié)果;
  • 限制查詢數(shù)量(如分頁查詢),減少關聯(lián)查詢次數(shù)。

5.2 合理使用別名避免字段沖突

多表查詢時,若主表與關聯(lián)表有同名字段(如id、name),需通過別名區(qū)分,否則映射結(jié)果會被覆蓋。

-- 錯誤:未用別名,o.id會覆蓋u.id
SELECT u.id, u.name, o.id, o.name 
FROM user u JOIN order o ON u.id = o.user_id

-- 正確:用別名區(qū)分
SELECT 
    u.id AS user_id, u.name AS user_name,
    o.id AS order_id, o.name AS order_name

5.3 按需查詢關聯(lián)數(shù)據(jù)

并非所有場景都需要查詢關聯(lián)數(shù)據(jù)(如列表頁展示用戶基本信息,無需查詢訂單),應根據(jù)場景設計不同查詢:

  • 簡單查詢:僅查詢主表數(shù)據(jù)(無關聯(lián));
  • 詳情查詢:查詢主表+關聯(lián)數(shù)據(jù)(通過連接查詢)。

5.4 延遲加載(按需加載關聯(lián)數(shù)據(jù))

MyBatis支持延遲加載(懶加載):查詢主表數(shù)據(jù)時不加載關聯(lián)數(shù)據(jù),僅當訪問關聯(lián)屬性時才觸發(fā)關聯(lián)查詢,適合“大部分場景不需要關聯(lián)數(shù)據(jù)”的場景。

開啟延遲加載(在MyBatis配置文件中):

<settings>
    <setting name="lazyLoadingEnabled" value="true"/> <!-- 全局開啟延遲加載 -->
    <setting name="aggressiveLazyLoading" value="false"/> <!-- 按需加載(訪問時才加載) -->
</settings>

使用場景:詳情頁默認展示用戶信息,點擊“查看訂單”按鈕才加載訂單數(shù)據(jù)(通過代碼觸發(fā)關聯(lián)屬性訪問)。

六、常見問題與避坑指南

6.1 關聯(lián)對象為null(映射失?。?/h3>

問題:關聯(lián)對象(如idCard)為null,但數(shù)據(jù)庫存在關聯(lián)數(shù)據(jù)。

原因

  • resultMapcolumn與SQL查詢的字段名不匹配(如SQL用card_id,resultMapcolumn="id");
  • 表連接條件錯誤(如JOIN條件不正確,導致關聯(lián)數(shù)據(jù)未查詢到);
  • 關聯(lián)表無匹配數(shù)據(jù)(正常情況,如用戶未綁定身份證,idCardnull)。

解決方案

  • 檢查resultMapcolumn是否與SQL查詢的字段(含別名)一致;
  • 單獨執(zhí)行SQL,確認關聯(lián)數(shù)據(jù)是否被正確查詢;
  • 若允許關聯(lián)數(shù)據(jù)為null,無需處理(正常邏輯)。

6.2 集合數(shù)據(jù)重復(一條數(shù)據(jù)被多次映射)

問題collection映射的列表中,同一條數(shù)據(jù)被重復添加(如一個訂單出現(xiàn)多次)。

原因

  • 未正確配置id標簽:resultMap中未用id標簽指定關聯(lián)對象的唯一標識(如訂單的id),MyBatis無法判斷數(shù)據(jù)是否重復;
  • SQL查詢返回重復數(shù)據(jù)(如JOIN導致主表數(shù)據(jù)被關聯(lián)表數(shù)據(jù)重復)。

解決方案

  • 為關聯(lián)對象配置id標簽(collection內(nèi)的id),指定唯一標識字段:
<collection property="orders" ofType="Order">
    <id column="order_id" property="id"/> <!-- 關鍵:指定訂單唯一標識 -->
    <!-- 其他字段 -->
</collection>
  • 優(yōu)化SQL,避免返回重復數(shù)據(jù)(如使用DISTINCT或調(diào)整JOIN邏輯)。

6.3 嵌套查詢參數(shù)傳遞錯誤

問題:嵌套查詢時,column傳遞的參數(shù)不正確,導致關聯(lián)查詢無結(jié)果。

解決方案

  • 確保column的值與主查詢返回的字段名一致:
<!-- 主查詢返回字段為user_id -->
<select id="selectUser" resultMap="UserMap">
    SELECT id AS user_id, username FROM user
</select>

<!-- 嵌套查詢需用主查詢的字段名作為參數(shù) -->
<association select="selectOrder" column="user_id"/> <!-- 正確:column="user_id" -->
  • 傳遞多個參數(shù)時,用column="{key1=col1, key2=col2}"
<association select="selectByParams" column="{id=user_id, name=user_name}"/>

總結(jié):關聯(lián)查詢的核心要點
MyBatis關聯(lián)查詢通過resultMapassociationcollection標簽,實現(xiàn)了多表數(shù)據(jù)到Java對象關聯(lián)關系的映射,核心要點如下:

  1. 標簽選擇
  • 一對一用association(映射單個對象);
  • 一對多/多對多用collection(映射集合)。
  1. 查詢方式
  • 優(yōu)先用連接查詢(單輪JOIN查詢,無N+1問題,性能好);
  • 嵌套查詢僅用于“關聯(lián)數(shù)據(jù)按需加載”場景(需注意N+1問題)。
  1. 優(yōu)化技巧
  • 用別名區(qū)分同名字段,避免映射沖突;
  • 配置id標簽確保關聯(lián)數(shù)據(jù)不重復;
  • 避免查詢無關字段,減少數(shù)據(jù)傳輸量。

到此這篇關于MyBatis的關聯(lián)查詢實現(xiàn)(一對一、一對多、多對多)的文章就介紹到這了,更多相關MyBatis 關聯(lián)查詢內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java Properties作為集合三個方法詳解

    Java Properties作為集合三個方法詳解

    Properties是JDK1.0中引入的java類,目前也在項目中大量使用,主要用來讀取外部的配置,那除了這個,你對它其他的一些api也了解嗎? 你了解它是怎么實現(xiàn)的嗎? 如果不清楚的話,就通過本篇文章帶你一探究竟
    2022-11-11
  • Java 數(shù)據(jù)結(jié)構之堆的概念與應用

    Java 數(shù)據(jù)結(jié)構之堆的概念與應用

    堆是一顆完全二叉樹,在這棵樹中,所有父節(jié)點都滿足大于等于其子節(jié)點的堆叫大根堆,所有父節(jié)點都滿足小于等于其子節(jié)點的堆叫小根堆,堆雖然是一顆樹,但是通常存放在一個數(shù)組中,父節(jié)點和孩子節(jié)點的父子關系通過數(shù)組下標來確定
    2021-10-10
  • Java Math類、Random類、System類及BigDecimal類用法示例

    Java Math類、Random類、System類及BigDecimal類用法示例

    這篇文章主要介紹了Java Math類、Random類、System類及BigDecimal類用法,結(jié)合實例形式分析了java數(shù)值運算相關的Math類、Random類、System類及BigDecimal類基本功能與使用技巧,需要的朋友可以參考下
    2019-03-03
  • Java自定義注解用法實例小結(jié)

    Java自定義注解用法實例小結(jié)

    這篇文章主要介紹了Java自定義注解用法,結(jié)合實例形式總結(jié)分析了java常見的自定義注解類型、功能、用法及操作注意事項,需要的朋友可以參考下
    2019-09-09
  • Spring Boot中@value的常見用法及案例

    Spring Boot中@value的常見用法及案例

    @Value注解是Spring框架中強大且常用的注解之一,本文主要介紹了SpringBoot中@value的常見用法及案例,具有一定的參考價值,感興趣的可以了解一下
    2023-09-09
  • java制作帶界面的聊天工具

    java制作帶界面的聊天工具

    這篇文章主要教大家如何利用java制作帶界面的聊天工具,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • spring整合shiro框架的實現(xiàn)步驟記錄

    spring整合shiro框架的實現(xiàn)步驟記錄

    Shiro是一個強大易用的Java安全框架,提供了認證、授權、加密和會話管理等功能。下面這篇文章主要給大家介紹了關于spring整合shiro框架的實現(xiàn)步驟,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2018-05-05
  • java連接mysql數(shù)據(jù)庫詳細步驟解析

    java連接mysql數(shù)據(jù)庫詳細步驟解析

    以下是對java連接mysql數(shù)據(jù)庫的具體詳細步驟進行了分析介紹,需要的朋友可以過來參考下
    2013-08-08
  • SpringCloud Finchley+Spring Boot 2.0 集成Consul的方法示例(1.2版本)

    SpringCloud Finchley+Spring Boot 2.0 集成Consul的方法示例(1.2版本)

    這篇文章主要介紹了SpringCloud Finchley+Spring Boot 2.0 集成Consul的方法示例(1.2版本),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-08-08
  • Java世界時區(qū)自動計算及時間生成方法詳解

    Java世界時區(qū)自動計算及時間生成方法詳解

    這篇文章主要為大家詳細介紹了Java中世界時區(qū)自動計算及時間生成的方法,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2024-12-12

最新評論

德钦县| 洪泽县| 安平县| 保靖县| 岳阳县| 富裕县| 兴义市| 团风县| 正定县| 盐津县| 长乐市| 汤阴县| 靖安县| 井陉县| 合江县| 公安县| 忻城县| 乐至县| 大安市| 同心县| 新野县| 甘洛县| 博爱县| 内丘县| 沁水县| 远安县| 丹巴县| 三河市| 东台市| 孝感市| 舟山市| 峨眉山市| 平武县| 扎鲁特旗| 始兴县| 涿鹿县| 江津市| 邯郸县| 四川省| 天镇县| 靖边县|