day07-MyBatis的關聯映射01

来源:https://www.cnblogs.com/liyuelian/archive/2023/02/28/17166430.html
-Advertisement-
Play Games

MyBatis的關聯映射 Mybatis的關聯映射 實際的開發中,對資料庫的操作常常會涉及到多張表,這在面向對象中就涉及到了對象與對象之間的關聯關係。針對多表之間的操作,MyBatis提供了關聯映射,通過關聯映射就可以很好的處理對象與對象之間的關聯關係。 1.關聯關係概述 在關係型資料庫中,多表之間 ...


MyBatis的關聯映射

Mybatis的關聯映射

實際的開發中,對資料庫的操作常常會涉及到多張表,這在面向對象中就涉及到了對象與對象之間的關聯關係。針對多表之間的操作,MyBatis提供了關聯映射,通過關聯映射就可以很好的處理對象與對象之間的關聯關係。

1.關聯關係概述

在關係型資料庫中,多表之間存在著三種關係,分別是一對一,一對多,多對多。

image-20230228175005921
  • 一對一:在任意一個表中引入另外一個表的主鍵作為外鍵。

  • 一對多:在多個表中都引入了某一個表的主鍵作為外鍵

  • 多對多:需要用一張中間表表示多對多的關係,這張中間表引入兩張表的主鍵作為外鍵。

一般來說一個對象映射一張表,因此一對一的關係就是在A類中定義B類屬性,一對多的關係就是在A類中定義List< B> 的屬性,多對多就是分別在A、B類中定義對方的List 屬性。

2.一對一

一對一關係是一個基本的映射關係,比如Person(人)--IDCard(身份證),我們可以通過如下兩種方式實現:

  1. 通過配置XxxMapper.xml實現1對1 [配置方式]
  2. 通過註解的方式實現1對1 [註解方式]

2.1配置方式

2.1.1環境搭建

配置映射文件來實現一對一的映射關係,實現級聯查詢,要求通過person可以獲取到對應的idencard信息

關於級聯查詢:若表A中有一個外鍵引用了表B的主鍵,A表就是子表,B表就是父表。當查詢表A的數據時,通過表A的外鍵將表B的記錄也查找出來,這就是級聯查詢。相應的還有級聯刪除,當刪除B表的記錄時,會先將A表中關聯的記錄刪掉

(1)person表和 idencard表

-- 創建 idencard 表
-- 記錄身份證
CREATE TABLE `idencard`(
`id` INT PRIMARY KEY AUTO_INCREMENT,
`card_sn` VARCHAR(32) NOT NULL DEFAULT ''
)CHARSET utf8;
INSERT INTO `idencard` VALUES(1,'123456789098765');


-- 創建person表
CREATE TABLE `person`(
`id` INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(32) NOT NULL DEFAULT '',
`card_id` INT, -- 對應idencard表的主鍵-id
FOREIGN KEY (`card_id`) REFERENCES idencard (`id`)-- card_id作為外鍵
)CHARSET utf8;
INSERT INTO `person` VALUES(1,'張三',1);

(2)實體類 IdenCard 和 Person

package com.li.entity;

/**
 * @author 李
 * @version 1.0
 */
public class IdenCard {
    private Integer id;
    private String card_sn;
    //省略setter,getter,toString方法
}
package com.li.entity;

/**
 * @author 李
 * @version 1.0
 */
public class Person {
    private Integer id;
    private String name;
    private IdenCard card;
    //省略setter,getter,toString方法
}

(3)PersonMapper 介面

package com.li.mapper;

import com.li.entity.Person;

/**
 * @author 李
 * @version 1.0
 */
public interface PersonMapper {
    //通過Person的id獲取到Person,包括這個Person關聯的IdenCard對象(級聯操作)
    public Person getPersonById(Integer id);
}

2.1.2方式1:多表聯查

mybatis – MyBatis 3 | XML 映射器

PersonMapper.xml映射文件實現級聯查詢,實現方法是使用多表聯查,返回的數據通過resultMap結果映射

<mapper namespace="com.li.mapper.PersonMapper">
    <!--1.介面聲明:public Person getPersonById(Integer id);
        2.通過Person的id獲取到Person,包括這個Person關聯的IdenCard對象(級聯操作)
        3.返回類型如果配置成resultType="Person",不能實現級聯查詢,
		在返回的person對象中IdenCard屬性對象為 null
        4.因此需要使用自定義resultMap,在resultMap中指定級聯關係-->
    <select id="getPersonById" parameterType="Integer" resultMap="PersonResultMap">
        SELECT * FROM `person`,`idencard` WHERE `person`.`id`= #{id} AND
        `person`.`card_id` = `idencard`.`id`;
    </select>

    <!--association – 一個複雜類型的關聯;許多結果將包裝成這種類型嵌套結果映射 – 關聯可以是
		resultMap 元素,或是對其它結果映射的引用
    	1.property="card" 表示 Person對象的card屬性
    	2.javaType="IdenCard" 表示card屬性的類型-->
    <resultMap id="PersonResultMap" type="Person">
        <!--id標簽–一個ID結果(就是主鍵);標記出作為主鍵的結果可以幫助提高整體性能-->
         <!--這裡的property表示Person類的屬性名,column表示對應表的欄位-->
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <association property="card" javaType="IdenCard">
            <!--這裡的property表示IdenCard類的屬性名,column表示表的欄位名-->
            <result property="id" column="id"/>
            <result property="card_sn" column="card_sn"/>
        </association>
    </resultMap>
</mapper>

測試:

@Test
public void getPersonById() {
    Person person = personMapper.getPersonById(1);
    System.out.println("person=" + person);
    if (sqlSession != null) {
        sqlSession.close();
    }
}
image-20230228194043902

2.2.3方式2:分解為多次單表操作(推薦使用)

第一種方式使用了多表聯查的形式實現級聯查詢,但是如果涉及的表過多,sql語句可讀性就會變差。第二種方式的核心思想是將多表聯查分解成單表操作,這樣更簡潔,易於維護,而且可以復用你寫好的方法,推薦使用

(1)創建IdenCardMapper介面

public interface IdenCardMapper {
    //根據id獲取到身份證序列號
    public IdenCard getIdenCardById(Integer id);
}

(2)在IdenCardMapper的映射文件中實現該方法

<mapper namespace="com.li.mapper.IdenCardMapper">
    <!--配置實現public IdenCard getIdenCardById(Integer id);-->
    <select id="getIdenCardById" parameterType="Integer" resultType="IdenCard">
        SELECT * FROM `idencard` WHERE `id` = #{id}
    </select>
</mapper>

(3)PersonMapper介面

//通過Person的id獲取到Person,包括這個Person關聯的IdenCard對象(方式2)
public Person getPersonById2(Integer id);

(4)實現PersonMapper介面的映射文件

   1. 先通過 SELECT * FROM person WHERE id =#{id} 返回 person 信息
   2. 以第一個操作返回的 card_id 欄位數據,作為條件再次查詢,得到對應的 IdenCard 數據

如果第一個操作使用了別名,那麼返回的時候的欄位也是別名,因此第二個操作也要使用別名才能匹配到

<!--通過Person的id獲取到Person,包括這個Person關聯的IdenCard對象(方式2)
    介面方法:public Person getPersonById2(Integer id);-->
<resultMap id="PersonResultMap2" type="Person">
    <id property="id" column="id"/>
    <result property="name" column="name"/>
    <!--第二種方式的核心思想是將多表聯查操作分解成單表操作,
    這樣更簡潔,易於維護,復用性更強,推薦使用-->
    <!--1.property="card"表示Person對象的card屬性
        2.column="card_id"是SELECT * FROM person WHERE id = #{id}語句返回的card_id欄位名/別名
        3.返回的欄位card_id信息/數據會作為getIdenCardById()的入參來執行方法-->
    <association property="card" column="card_id"
                 select="com.li.mapper.IdenCardMapper.getIdenCardById"/>
</resultMap>
<select id="getPersonById2" parameterType="Integer" resultMap="PersonResultMap2">
    SELECT * FROM person WHERE id = #{id};
</select>

測試結果:

可以看到底層執行了兩次sql查詢操作。首先對person表進行查詢,查詢結果(card_id)作為第二張表的查詢條件(id),再對idencard表進行查詢。

image-20230228204133095

2.2註解方式

通過註解的方式來實現一對一的映射關係,實現級聯查詢,通過person可以獲取到對應的idencard的信息。這裡只進行方式二的演示。

在實際開發中還是推薦使用配置方式

(1)註解實現方法

IdenCardMapperAnnotation 介面:

package com.li.mapper;

import com.li.entity.IdenCard;
import org.apache.ibatis.annotations.Select;

/**
 * @author 李
 * @version 1.0
 * 使用註解的方式實現一對一的映射
 */
public interface IdenCardMapperAnnotation {
    //根據id獲取到身份證序列號
    @Select(value = "SELECT * FROM `idencard` WHERE `id` = #{id}")
    public IdenCard getIdenCardById(Integer id);
}

PersonMapperAnnotation 介面:

package com.li.mapper;

import com.li.entity.Person;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;

/**
 * @author 李
 * @version 1.0
 */
public interface PersonMapperAnnotation {
    //通過Person的id獲取到Person,包括這個Person關聯的IdenCard對象
    //註解的形式就是對前面xml配置方式的體現
    @Select(value = "SELECT * FROM person WHERE id = #{id}")//如果這裡返回的欄位使用了別名,則@result的card_id也要使用該別名
    @Results({//配置返回數據的映射
            @Result(id = true, property = "id", column = "id"),
            @Result(property = "name", column = "name"),
            @Result(property = "card", column = "card_id",
                    one = @One(select = "com.li.mapper.IdenCardMapper.getIdenCardById"))
    })
    public Person getPersonById(Integer id);
}

(2)測試

@Test
public void getIdenCardById() {
    Person person = personMapperAnnotation.getPersonById(1);
    System.out.println("person=" + person);
    if (sqlSession != null) {
        sqlSession.close();
    }
}
image-20230228210319588

2.3註意事項

一張表是否設置了外鍵,對MyBatis進行對象級聯映射沒有影響,外鍵只是對錶本身數據的約束

2.4練習

前面我們講解的是查詢Person可以級聯查詢到IdenCard,如果要求通過查詢IdenCard,也可以級聯查詢到Person,應該如何解決?


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • tips:如果本文對你有用,請愛心點個贊,提高排名,讓這篇文章幫助更多的人。謝謝大家!比心❤~ 如果解決不了,可以在文末加我微信,進群交流一起學習探討。 背景 項目的要求需要實現規範化,針對項目內所有的滾動條做優化,需要按照UE調整實現:滾動時出現滾動條,停留三秒後,自動消失 由於是就項目的優化,所 ...
  • 我們是袋鼠雲數棧 UED 團隊,致力於打造優秀的一站式數據中台產品。我們始終保持工匠精神,探索前端道路,為社區積累並傳播經驗價值。 前言 數棧作為雲原⽣⼀站式⼤數據開發平臺,從2016年發佈第⼀個版本開始,數棧就始終堅持著以技術為 核⼼、安全為底線、提效為⽬標、中台為戰略的思想,堅定不移地⾛國產化信 ...
  • 本文是系列第四篇。系列文章: 現代圖片性能優化及體驗優化指南 - 圖片類型及 Picture 標簽的使用 現代圖片性能優化及體驗優化指南 - 響應式圖片方案 現代圖片性能優化及體驗優化指南 - # 縮放精細化展示及避免佈局偏移、拉伸 圖片資源,在我們的業務中可謂是占據了非常大頭的一環,尤其是其對帶寬 ...
  • cola前言 COLA提供了一整套代碼架構,拿來即用。 其中包含了很多架構設計思想,包括討論度很高的領域驅動設計DDD等。 COLA 的分層是一種經過改良的三層架構,主要是講傳統的業務邏輯層拆分為展示層、應用層、領域層和基礎設施層。 展示層(Presentation Layer):負責以 Rest ...
  • 1.簡介 定義:將某個對象中圍繞某個主題的一些列行為委托給一個代理對象去執行,代理對象將控制和管理對原有對象的訪問,調用者想要訪問目標對象,必須通過代理對象去間接訪問,代理對象在調用方和目標對象之間可以起到”中介“的作用。代理一詞本身,其實就可以很好發現的關鍵點,如果暫時無法理解晦澀的概念,那麼在閱 ...
  • *以下內容為本人的學習筆記,如需要轉載,請聲明原文鏈接 微信公眾號「englyf」https://mp.weixin.qq.com/s/y-npGelPJwmx3iNvHaXRTg 本文上接《Python:Excel自動化實踐入門篇 甲》 正文開始之前,提醒一下朋友們,送圖書的活動還在繼續,朋友們請 ...
  • Spring Boot 支持 Java Util Logging,Log4J,Log4J2 和 Logback 等日誌框架,預設採用 Logback 日誌。 在實際 Spring Boot 項目中使用 Spring Boot 預設日誌配置是不能夠滿足實際生產及開發需求的,需要選定適合的日誌輸出框架, ...
  • Nacos Nacos體系架構 領域模型 Nacos 領域模型描述了服務與實例之間的邊界和層級關係。Nacos 的服務領域模型是以“服 務”為維度構建起來的,這個服務並不是指集群中的單個伺服器,而是指微服務的服務名。 “服務”是 Nacos 中位於最上層的概念,在服務之下,還有集群和實例的概念。 服 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...