MyBatis之關(guān)聯(lián)查詢

我都知道Java對(duì)象存在三種關(guān)聯(lián)關(guān)系:一對(duì)一、一對(duì)多、多對(duì)多。本文將詳細(xì)講解MyBatis的關(guān)聯(lián)查詢方式。

關(guān)聯(lián)元素

  • 一對(duì)一關(guān)系:association
  • 一對(duì)多關(guān)系:collection
  • 鑒別器映射:discriminator

查詢方式

無論是一對(duì)一還是一對(duì)多都存在兩種查詢方式
嵌套結(jié)果:通過查詢結(jié)果進(jìn)行映射至相應(yīng)的JavaBean(例如連接查詢)
嵌套查詢:先查一張表,然后通過這張表的結(jié)果去查其他表

數(shù)據(jù)庫表關(guān)系

現(xiàn)在有三張表,表字段如下

  1. company:
id code name source create_time
  1. company_ext:
id remark create_time
  1. company_price:
id company_id date price create_time update_time

其中company.id與company_ext.id對(duì)應(yīng),且為一對(duì)一的關(guān)系。
company.id與company_price.company_id對(duì)應(yīng),即為一對(duì)多的關(guān)系。

JavaBean

這里只列出屬性名,set、get等方法,省略

public class Company {

    private String id;
    private String code;
    private String name;
    private String source;
    private Date createTime;
    
    ......
}
public class CompanyExt {
    private String id;
    private String remark;
    private Date createTime;

    ......
}
public class CompanyAndExt {
    private String id;
    private String code;
    private String name;
    private String source;
    private Date createTime;

    private CompanyExt companyExt;

    ......
}
public class StockPrice {
    private String id;
    private String companyId;
    private String date;
    private String price;
    private String createTime;

    ......
}
public class CompanyPrice {

    private String id;
    private String code;
    private String name;
    private String source;
    private Date createTime;

    private List<StockPrice> stockPriceList;

    ......
}

接口類:

package com.test.mapper;

import java.util.List;

import com.test.dto.*;
import org.apache.ibatis.annotations.Param;

public interface CompanyMapper {
    // 一對(duì)一
    // 嵌套結(jié)果、嵌套查詢
    CompanyAndExt getCompanyAndExtById(String id);
    // 嵌套查詢
    CompanyExt getCompanyExtById(String id);

    // 一對(duì)多
    // 嵌套結(jié)果、嵌套查詢
    CompanyPrice getCompanyPriceById(String id);
    // 嵌套查詢
    List<StockPrice> listStockPriceByCompanyId(String companyId);

}

一對(duì)一(association)

  1. 嵌套結(jié)果
    a. association常用元素如下
    property:所映射的屬性名
    javaType:所映射的屬性對(duì)應(yīng)的Java屬性類型
    resultMap:使用已有的resultMap
    columnPrefix:子標(biāo)簽result(id)的column的前綴
    b. 示例源碼
    <!--一對(duì)一的嵌套結(jié)果-->
    <resultMap id="companyResultMap" type="com.test.dto.Company">
        <id property="id" column="id"/>
        <result property="code" column="code"/>
        <result property="name" column="name"/>
        <result property="source" column="source"/>
        <result property="createTime" column="create_time"/>
    </resultMap> 

    <resultMap id="companyAndExtResultMap" extends="companyResultMap" type="com.test.dto.CompanyAndExt">
    <association property="companyExt" javaType="com.test.dto.CompanyExt" columnPrefix="ext_">
    <id column="id" property="id" />
    <result column="remark" property="remark" />
    <result column="create_time" property="createTime" />
    </association>
    </resultMap>

    <select id="getCompanyAndExtById" resultMap="companyAndExtResultMap">
    SELECT c.`id`,c.`code`,c.`name`,c.`source`,c.`create_time`, ce.`id` ext_id, ce.`remark` ext_remark, ce.`create_time` ext_create_time FROM company c, company_ext ce WHERE c.`id` = ce.`id` AND c.`id` = #{id,jdbcType=VARCHAR};
    </select>

補(bǔ)充:
resultMap 下的extends元素,顧名思義,可以繼承另外一個(gè)resultMap的映射配置
關(guān)聯(lián)表查詢時(shí),使用前綴對(duì)后期的維護(hù)提供很大的便利

  1. 嵌套查詢
    a. association常用元素如下
    select:使用嵌套查詢方法
    column:主查詢的結(jié)果作為嵌套查詢的參數(shù)
    fetchType:是否使用懶加載,'lazy'為懶加載,'eager'為積極加載
    b.示例代碼
    <!--一對(duì)一的嵌套查詢-->

    <resultMap id="companyExt" type="com.test.dto.CompanyExt">
        <id column="id" property="id"/>
        <result column="remark" property="remark"/>
        <result column="create_time" property="createTime"/>
    </resultMap>

    <sql id="companyExtSelectColumns">
        `id`,`remark`,`create_time`
    </sql>

    <select id="getCompanyExtById" resultMap="companyExt">
        SELECT
        <include refid="companyExtSelectColumns"/>
        FROM company_ext WHERE id = #{id,jdbcType=VARCHAR};
    </select>

    <resultMap id="companyAndExtResultMap" extends="companyResultMap" type="com.test.dto.CompanyAndExt">
        <association property="companyExt" fetchType="lazy" column="id" javaType="com.test.dto.CompanyExt"
                     select="com.test.mapper.CompanyMapper.getCompanyExtById"/>
    </resultMap>

    <select id="getCompanyAndExtById" resultMap="companyAndExtResultMap">
        SELECT
        <include refid="selectColumns"/>
        FROM company c WHERE c.id = #{id,jdbcType=INTEGER}
    </select>

補(bǔ)充說明:
column屬性:column="id",表示查詢結(jié)果與嵌套方法入?yún)⒚Q相同,且入?yún)⒅挥幸粋€(gè)。多個(gè)參數(shù)使用column="{resultId=id,resultCode=code}",resultId、resultCode都為主查詢的結(jié)果名
fetchType屬性:fetchType="lazy" 表示使用懶加載,即程序中實(shí)際使用了CompanyAndExt.CompanyExt里的屬性或方法,才進(jìn)行查詢,這樣會(huì)大大增加查詢效率。

一對(duì)多(collection)

collection支持的屬性及其屬性的作用于association完全相同(詳情可見上文)

  1. 嵌套結(jié)果
    a. myBatis中的javaType與ofType的區(qū)別
    都是用于指定對(duì)象類型,javaType是用來指定映射pojo中的屬性的類型,而ofType是用來指定映射至集合中的pojo類型。
    b. 示例源碼
<!--一對(duì)多的嵌套結(jié)果-->
    <resultMap id="companyResultMap" type="com.test.dto.Company">
        <id property="id" column="id"/>
        <result property="code" column="code"/>
        <result property="name" column="name"/>
        <result property="source" column="source"/>
        <result property="createTime" column="create_time"/>
    </resultMap> 

    <resultMap id="companyPriceResultMap" extends="companyResultMap" type="com.test.dto.CompanyPrice">
        <collection property="stockPriceList" ofType="com.test.dto.StockPrice" columnPrefix="cp_">
            <id column="id" property="id"/>
            <result column="company_id" property="companyId"/>
            <result column="date" property="date"/>
            <result column="price" property="price"/>
            <result column="create_time" property="createTime"/>
        </collection>
    </resultMap>

    <select id="getCompanyPriceById" resultMap="companyPriceResultMap">
        SELECT
        c.`id`,
        c.`name`,
        c.`code`,
        c.`source`,
        c.`create_time`,
        cp.`id` AS cp_id,
        cp.`company_id` AS cp_company_id,
        cp.`date` AS cp_date,
        cp.`price` AS cp_price,
        cp.`create_time` AS cp_create_time
        FROM
        company AS c ,
        company_price AS cp
        WHERE
        c.`id` = cp.`company_id` AND
        c.`id` = #{id,jdbcType=VARCHAR};
    </select>
  1. 嵌套查詢
    a. 示例源碼
    <!--一對(duì)多的嵌套查詢-->
    <resultMap id="stockPriceResultMap" type="com.test.dto.StockPrice">
        <id column="id" property="id"/>
        <result column="company_id" property="companyId"/>
        <result column="date" property="date"/>
        <result column="price" property="price"/>
        <result column="create_time" property="createTime"/>
    </resultMap>

    <select id="listStockPriceByCompanyId" resultMap="stockPriceResultMap">
        SELECT
        cp.`id`,
        cp.`company_id`,
        cp.`date`,
        cp.`price`,
        cp.`create_time`
        FROM
        company_price AS cp
        WHERE
        cp.company_id = #{companyId,jdbcType=VARCHAR}
    </select>


    <resultMap id="companyPriceResultMap" extends="companyResultMap" type="com.test.dto.CompanyPrice">
        <collection property="stockPriceList" column="id" fetchType="lazy"
                     select="com.test.mapper.CompanyMapper.listStockPriceByCompanyId"/>
    </resultMap>

    <select id="getCompanyPriceById" resultMap="companyPriceResultMap">
        SELECT
        <include refid="selectColumns"/>
        FROM company c WHERE c.id = #{id,jdbcType=VARCHAR}
    </select>

鑒別器映射(discriminator)

鑒別器非常的容易理解,因?yàn)?,它非常像java中的switch語句
我們直接來看示例代碼,然后根據(jù)示例代碼進(jìn)行講解

    <resultMap id="companyPriceResultMap1" type="com.test.dto.CompanyPrice">
        ......
    </resultMap>
    <resultMap id="companyPriceResultMap2" type="com.test.dto.CompanyPrice">
        ......
    </resultMap>

    <resultMap id="companyPriceResultMap" type="com.test.dto.CompanyPrice">
        <discriminator javaType="int" column="code">
            <case value="1" resultMap="companyPriceResultMap1" />
            <case value="2" resultMap="companyPriceResultMap2" />
        </discriminator>
    </resultMap>

說明:

  1. discriminator標(biāo)簽有兩個(gè)屬性:
    a. column:需要鑒別的列
    b. javaType:指定列的數(shù)據(jù)類型,用于比較
  2. discriminator的子標(biāo)簽case有三個(gè)屬性
    a. value:鑒別的值
    b. resultMap:當(dāng)鑒別值匹配時(shí),使用該resultMap指定的映射,resultMap優(yōu)先級(jí)高于resultType
    c. resultType:當(dāng)鑒別值匹配時(shí),使用該resultType指定的映射

特別說明:

  1. 本博客為自己的學(xué)習(xí)筆記,因此存在知識(shí)點(diǎn)覆蓋不全,部分功能遺漏,后續(xù)逐步補(bǔ)充;
  2. 文中如果存在錯(cuò)誤的地方,還請(qǐng)留言指出,我會(huì)第一時(shí)間糾正;
  3. 如果有什么不滿(需要補(bǔ)充的知識(shí)點(diǎn)、優(yōu)化點(diǎn)等),還請(qǐng)不吝指教,我會(huì)盡快響應(yīng)處理,謝謝!
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容