MyBatis之关联查询

我都知道Java对象存在三种关联关系:一对一、一对多、多对多。本文将详细讲解MyBatis的关联查询方式。

关联元素

  • 一对一关系:association
  • 一对多关系:collection
  • 鉴别器映射:discriminator

查询方式

无论是一对一还是一对多都存在两种查询方式
嵌套结果:通过查询结果进行映射至相应的JavaBean(例如连接查询)
嵌套查询:先查一张表,然后通过这张表的结果去查其他表

数据库表关系

现在有三张表,表字段如下

  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对应,且为一对一的关系。
company.id与company_price.company_id对应,即为一对多的关系。

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 {
    // 一对一
    // 嵌套结果、嵌套查询
    CompanyAndExt getCompanyAndExtById(String id);
    // 嵌套查询
    CompanyExt getCompanyExtById(String id);

    // 一对多
    // 嵌套结果、嵌套查询
    CompanyPrice getCompanyPriceById(String id);
    // 嵌套查询
    List<StockPrice> listStockPriceByCompanyId(String companyId);

}

一对一(association)

  1. 嵌套结果
    a. association常用元素如下
    property:所映射的属性名
    javaType:所映射的属性对应的Java属性类型
    resultMap:使用已有的resultMap
    columnPrefix:子标签result(id)的column的前缀
    b. 示例源码
    <!--一对一的嵌套结果-->
    <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>

补充:
resultMap 下的extends元素,顾名思义,可以继承另外一个resultMap的映射配置
关联表查询时,使用前缀对后期的维护提供很大的便利

  1. 嵌套查询
    a. association常用元素如下
    select:使用嵌套查询方法
    column:主查询的结果作为嵌套查询的参数
    fetchType:是否使用懒加载,'lazy'为懒加载,'eager'为积极加载
    b.示例代码
    <!--一对一的嵌套查询-->

    <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>

补充说明:
column属性:column="id",表示查询结果与嵌套方法入参名称相同,且入参只有一个。多个参数使用column="{resultId=id,resultCode=code}",resultId、resultCode都为主查询的结果名
fetchType属性:fetchType="lazy" 表示使用懒加载,即程序中实际使用了CompanyAndExt.CompanyExt里的属性或方法,才进行查询,这样会大大增加查询效率。

一对多(collection)

collection支持的属性及其属性的作用于association完全相同(详情可见上文)

  1. 嵌套结果
    a. myBatis中的javaType与ofType的区别
    都是用于指定对象类型,javaType是用来指定映射pojo中的属性的类型,而ofType是用来指定映射至集合中的pojo类型。
    b. 示例源码
<!--一对多的嵌套结果-->
    <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. 示例源码
    <!--一对多的嵌套查询-->
    <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)

鉴别器非常的容易理解,因为,它非常像java中的switch语句
我们直接来看示例代码,然后根据示例代码进行讲解

    <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标签有两个属性:
    a. column:需要鉴别的列
    b. javaType:指定列的数据类型,用于比较
  2. discriminator的子标签case有三个属性
    a. value:鉴别的值
    b. resultMap:当鉴别值匹配时,使用该resultMap指定的映射,resultMap优先级高于resultType
    c. resultType:当鉴别值匹配时,使用该resultType指定的映射

特别说明:

  1. 本博客为自己的学习笔记,因此存在知识点覆盖不全,部分功能遗漏,后续逐步补充;
  2. 文中如果存在错误的地方,还请留言指出,我会第一时间纠正;
  3. 如果有什么不满(需要补充的知识点、优化点等),还请不吝指教,我会尽快响应处理,谢谢!
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容