1. 程式人生 > >MyBatis從入門到精通(十一):MyBatis高階結果對映之一對多對映

MyBatis從入門到精通(十一):MyBatis高階結果對映之一對多對映

最近在讀劉增輝老師所著的《MyBatis從入門到精通》一書,很有收穫,於是將自己學習的過程以部落格形式輸出,如有錯誤,歡迎指正,如幫助到你,不勝榮幸!

本篇部落格主要講解MyBatis中如何使用collection標籤實現查詢結果一對多對映。

1. 使用collection標籤

需求:根據使用者id查詢使用者資訊的同時獲取使用者擁有的角色,一個使用者可以擁有1個或多個角色。

一般情況下,不建議直接修改資料庫表對應的實體類。

所以這裡我們延用之前部落格中新建的類SysUserExtend,並新增如下程式碼,如下所示:

/**
 * 使用者的角色集合
 */
private List<SysRole> sysRoleList;

public List<SysRole> getSysRoleList() {
    return sysRoleList;
}

public void setSysRoleList(List<SysRole> sysRoleList) {
    this.sysRoleList = sysRoleList;
}

然後,我們在介面SysUserMapper中新增如下方法:

/**
 * 獲取所有的使用者以及對應的所有角色
 *
 * @return
 */
List<SysUserExtend> selectAllUserAndRoles();

接著,在對應的SysUserMapper.xml中新增如下程式碼:

<resultMap id="userRoleListMap" type="com.zwwhnly.mybatisaction.model.SysUserExtend" extends="sysUserMap">
    <collection property="sysRoleList" columnPrefix="role_"
                ofType="com.zwwhnly.mybatisaction.model.SysRole">
        <id property="id" column="id"/>
        <result property="roleName" column="role_name"/>
        <result property="enabled" column="enabled"/>
        <result property="createBy" column="create_by"/>
        <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
    </collection>
</resultMap>

因為我們在前面的部落格中已經建過角色表的roleMap:

<resultMap id="roleMap" type="com.zwwhnly.mybatisaction.model.SysRole">
    <id property="id" column="id"/>
    <result property="roleName" column="role_name"/>
    <result property="enabled" column="enabled"/>
    <result property="createBy" column="create_by"/>
    <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
</resultMap>

所以上面的collection標籤可以簡化為:

<collection property="sysRoleList" columnPrefix="role_"
            resultMap="com.zwwhnly.mybatisaction.mapper.SysRoleMapper.roleMap">
</collection>

新建介面對應的查詢程式碼,使用上面新建的userRoleListMap,如下所示:

<select id="selectAllUserAndRoles" resultMap="userRoleListMap">
    SELECT
        u.id,
        u.user_name,
        u.user_password,
        u.user_email,
        u.create_time,
        r.id role_id,
        r.role_name role_role_name,
        r.enabled role_enabled,
        r.create_by role_create_by,
        r.create_time role_create_time
    FROM sys_user u
    INNER JOIN sys_user_role ur ON u.id = ur.user_id
    INNER JOIN sys_role r ON ur.role_id = r.id
</select>

最後,在SysUserMapperTest測試類中新增如下測試方法:

@Test
public void testSelectAllUserAndRoles() {
    SqlSession sqlSession = getSqlSession();

    try {
        SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);

        List<SysUserExtend> sysUserList = sysUserMapper.selectAllUserAndRoles();
        System.out.println("使用者數:" + sysUserList.size());
        for (SysUserExtend sysUser : sysUserList) {
            System.out.println("使用者名稱:" + sysUser.getUserName());
            for (SysRole sysRole : sysUser.getSysRoleList()) {
                System.out.println("角色名:" + sysRole.getRoleName());
            }
        }
    } finally {
        sqlSession.close();
    }
}

執行測試程式碼,測試通過,輸出日誌如下:

DEBUG [main] - ==> Preparing: SELECT u.id, u.user_name, u.user_password, u.user_email, u.create_time, r.id role_id, r.role_name role_role_name, r.enabled role_enabled, r.create_by role_create_by, r.create_time role_create_time FROM sys_user u INNER JOIN sys_user_role ur ON u.id = ur.user_id INNER JOIN sys_role r ON ur.role_id = r.id

DEBUG [main] - ==> Parameters:

TRACE [main] - <== Columns: id, user_name, user_password, user_email, create_time, role_id, role_role_name, role_enabled, role_create_by, role_create_time

TRACE [main] - <== Row: 1, admin, 123456, [email protected], 2019-06-27 18:21:07.0, 1, 管理員, 1, 1, 2019-06-27 18:21:12.0

TRACE [main] - <== Row: 1, admin, 123456, [email protected], 2019-06-27 18:21:07.0, 2, 普通使用者, 1, 1, 2019-06-27 18:21:12.0

TRACE [main] - <== Row: 1001, test, 123456, [email protected], 2019-06-27 18:21:07.0, 2, 普通使用者, 1, 1, 2019-06-27 18:21:12.0

DEBUG [main] - <== Total: 3

使用者數:2

使用者名稱:admin

角色名:管理員

角色名:普通使用者

使用者名稱:test

角色名:普通使用者

2. MyBatis合併規則

觀察上面的日誌,我們的Sql語句查詢到了3條資料,在資料庫查詢的話,也是返回如下的資料:

但經過MyBatis配置的對映到,最後合併為了2個使用者,其中第1個使用者包含了2個角色,第2個使用者包含了1個角色,那麼MyBatis是根據什麼規則合併的呢?

MyBatis在處理結果的時候,會判斷結果是否相同,如果是相同的結果,則只會保留第一個結果,所以關鍵點就是MyBatis如何判斷結果是否相同。

判斷結果是否相同時,最簡單的情況就是在對映配置中至少有1個id標籤,上面使用的sysUserMap就配置了id標籤:

<id property="id" column="id"/>

一般情況下,id標籤配置的欄位為表的主鍵,如果是聯合主鍵,可以配置多個id標籤。

id標籤的作用就是在巢狀的對映配置時判斷資料是否相同,當配置id標籤時,MyBatis只需要逐條比較所有資料中id標籤配置的欄位值是否相同即可。

也可以不配置id標籤,將上面的程式碼修改為:

<result property="id" column="id"/>

使用result不會影響查詢結果,但是此時MyBatis就要對所有欄位進行比較,因此當欄位數為M時,如果查詢結果有N條,就需要比較M*N次,如果配置了id標籤,只需要比較N次即可,所以要儘可能的配置id標籤。

結合上面的例子,因為Sql的查詢結果中,前2條資料中使用者的id是相同的,所以會合併為1個使用者,所以最終的結果是2個使用者。

為了更清楚的理解id標籤的作用,我們將sysUserMap臨時修改為:

<resultMap id="sysUserMap" type="com.zwwhnly.mybatisaction.model.SysUser">
    <id property="userPassword" column="user_password"/>
    <result property="id" column="id"/>
    <result property="userName" column="user_name"/>
    <result property="userEmail" column="user_email"/>
    <result property="userInfo" column="user_info"/>
    <result property="headImg" column="head_img" jdbcType="BLOB"/>
    <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
</resultMap>

執行測試方法,輸出的部分日誌如下:

使用者數:1

使用者名稱:admin

角色名:管理員

角色名:普通使用者

因為3個使用者的密碼都是123456,所以查詢到的3條資料只保留了第一個使用者admin,包含了2個角色。

有的同學也許會問,為什麼不是擁有3個角色呢?

這是因為MyBatis會對巢狀查詢的每一級物件都進行屬性比較,MyBatis會先比較頂層的物件,如果SysUser部分相同,就繼續比較SysRole部分,如果SysRole不同,就會增加一個SysRole,如果相同就保留前一個。

如果SysRole還有下一級,依次按照規則去比較。

上面的“普通使用者”角色重複了,所以只保留了前1個,導致最終的結果中只包含2個角色而不是3個。

3. 原始碼及參考

原始碼地址:https://github.com/zwwhnly/mybatis-action.git,歡迎下載。

劉增輝《MyBatis從入門到精通》

4. 最後

打個小廣告,歡迎掃碼關注微信公眾號:「申城異鄉人」,不定期分享Java技術乾貨,讓我們一起進步。

相關推薦

MyBatis入門精通()MyBatis高階結果對映之一對映

最近在讀劉增輝老師所著的《MyBatis從入門到精通》一書,很有收穫,於是將自己學習的過程以部落格形式輸出,如有錯誤,歡迎指正,如幫助到你,不勝榮幸! 本篇部落格主要講解MyBatis中如何使用collection標籤實現查詢結果一對多對映。 1. 使用collection標籤 需求:根據使用者id查詢使用者

Spring Boot系列教程 Mybatis使用分頁外掛PageHelper

一.前言 上篇部落格中介紹了spring boot整合mybatis的方法,基於上篇文章這裡主要介紹如何使用分頁外掛PageHelper。在MyBatis中提供了攔截器介面,我們可以使用PageHelp最為一個外掛裝入到SqlSessionFactory,實現攔截器功能。

【QT】QT入門教程()QT自定義視窗

  首先是借鑑了網上的部落格,實現無邊框,自由拖動的自定義視窗效果。 #ifndef CUSTOMWINDOW_H #define CUSTOMWINDOW_H #include <QtGui> #include <QtWidg

Spring Boot2()Mybatis使用總結(自增長、條件、批量操作、表查詢等等)

一、前言 上次用Mybatis還是2017年做專案的時候,已經很久過去了。中途再沒有用過Mybatis。導致現在學習SpringBoot過程中遇到一些Mybatis的問題,以此做出總結(XML極簡模式)。當然只是實用方面的總結,具體就不深究♂了。這裡只總結怎麼用!!! (這次直接跳到十一,是因為中間是Rabb

NDK開發 入門到放棄(基本流程入門瞭解)

一、前言 ● NDK Native Development Kit(NDK)是一系列工具的集合。它提供了一系列的工具,幫助開發者快速開發C/C++的動態庫,並能自動將so和java一起打包成apk。 ● JNI Java Native Interface(JNI)標準是java平臺的

SpringMVC入門跨重定向請求傳遞資料

通常,當我們處理完POST請求之後,出於安全的考慮(防止使用者重新整理或後退而重新執行危險的POST請求),會將請求重定向,在前面,我們藉助了“redirect:”來實現這一功能。”redirect:”字首能夠讓重定向功能變得非常簡單,但是Spring為重定向功能還提供了一些

arcgis for js 入門到放棄初識和配置詳解

前言:去年因專案需要學習arcgis js,上手資料只有官網的api和demo,半年過去了資料還是很少,於是寫這個系列希望能幫助新手能快速入門。這東西我玩的時間也不長,各種不足和錯誤也希望大家能批評指正。 首先給出官網地址(https://developers.

RabbitMQ入門教程()訊息屬性Properties

簡介 傳送訊息可以為訊息指定一些引數 Delivery mode: 是否持久化,1 - Non-persistent,2 - Persistent Headers:Headers can have

mybatis-高階結果對映之一(你知道一對結果是如何合併的嗎)

在一對多的關係中, 主表的資料回對應關聯表中的多條資料。 因此, 查詢時就會查詢出多條結果, 所以, 向類似的情況我們會使用 List 來進行儲存關聯表中獲取到的資訊。 1 資料準備 建立以下的名為 mybatis 的資料庫, 並在其下建立4個表。 在此就不貼出來建表的 SQL 語句了 , 感興趣的

JavaEE MyBatis關聯對映之一(教材學習筆記)

在實際應用中,應用更多的是一對多,例如每一個使用者可以有多個訂單,在使用MyBatis中是怎樣處理一對多的關係呢,在MyBatis對映檔案中有一個resultMap元素,此元素包含一個<collection>子元素,MyBatis就是通過他來處理一對多關係的, 下面通過一個案例瞭

MyBatis的學習(七)——關聯對映之一關聯

本次部落格其它相關可以檢視之前的部落格的內容。 一對多使用到的主要是:collection 根據classes的id查詢對應的班級資訊,包括學生,老師 上一篇部落格已經建立classes和teacher表,這裡不再多說,本次建立student表即可: 定義student實

springmvc-mybatis之一對映

1.首先來個需求 1.一個訂單表和一個訂單詳情表,一個訂單可以有多個訂單詳情,訂單詳情裡面主要記錄了購買商品的名稱以及數量。那麼,現在要查詢一個訂單的詳細情況。也就是說這是一對多查詢,從訂單表裡用其id查詢訂單詳情表的所有記錄。 2. 實現 2.1首先實現

hibernate關聯對映之一&

package loaderman.b_one2Many; import java.util.HashSet; import java.util.Set; public class Dept { private int deptId; private String

SSH框架之Hibernate的關聯對映之一對映

關聯對映之一對多、多對一對映 一、需求: 部門與員工 一個部門有多個員工 【一對多】 多個員工,屬於一個部門 【多對一】 二、邏輯分析: 三、程式碼實現 1、javabean及對映檔案的配置: 1)Employee.java、Employ

MyBatis入門精通()MyBatis入門

最近在讀劉增輝老師所著的《MyBatis從入門到精通》一書,很有收穫,於是將自己學習的過程以部落格形式輸出,如有錯誤,歡迎指正,如幫助到你,不勝榮幸! 1. MyBatis簡介 ​ 2001年,Clinton Begin發起了一個名為iBATIS的開源專案,最初側重於密碼軟體的研發,後來發展成為一款基於Jav

MyBatis入門精通()使用association標籤實現巢狀查詢

最近在讀劉增輝老師所著的《MyBatis從入門到精通》一書,很有收穫,於是將自己學習的過程以部落格形式輸出,如有錯誤,歡迎指正,如幫助到你,不勝榮幸! 本篇部落格主要講解使用association標籤實現巢狀查詢的方法。 1. 明確需求 仍然延用上篇部落格中的需求:根據使用者id查詢使用者資訊的同時獲取該使用

MyBatis入門精通(二)使用collection標籤實現巢狀查詢

最近在讀劉增輝老師所著的《MyBatis從入門到精通》一書,很有收穫,於是將自己學習的過程以部落格形式輸出,如有錯誤,歡迎指正,如幫助到你,不勝榮幸! 本篇部落格主要講解使用collection標籤實現巢狀查詢的方法。 1. 需求升級 在上篇部落格中,我們實現了需求:根據使用者id查詢使用者資訊的同時獲取使用

MyBatis入門精通(四)MyBatis中使用型別處理器

最近在讀劉增輝老師所著的《MyBatis從入門到精通》一書,很有收穫,於是將自己學習的過程以部落格形式輸出,如有錯誤,歡迎指正,如幫助到你,不勝榮幸! 本篇部落格主要講解在MyBatis中如何使用型別處理器。 1. 明確需求 在設計之初,sys_role表的enabled欄位有2個可選值,其中0 代表禁用,1

MyBatis入門精通第一章配置MyBatis

從入門到精通 sim efault 入門到 eve lse version 例如 div <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC

MyBatis入門精通第一章實體類與Mapper.xml文件

1.0 style 返回值 spa map 命名 定義 當前 入門到精通 實體類: package tk.mybatis.simple.model; public class Country { public Long getId() {