Mybatis 关联查询

多表查询是在企业中必不可少的,无论多么简单的项目里都会出现多表查询操作。因为只要是关系型数据库,在设计表时都需要按照范式进行设计,为了减少数据冗余,都会拆成多个表。当需要表中数据时,在进行联合查询。

在MySQL学习时,知道表之间关系分为:一对一、一对多、多对多。这三种关系又细分为单向和双向。如果学习的是Hibernate框架,必须要严格区分开表之间的关系,然后才能使用Hibernate框架。但是在MyBatis框架中只有两种情况:当前表对应另外表是一行数据还是多行数据。转换到实体类上:当前实体类包含其他实体类一个对象还是多个对象。再转换到MyBatis的映射文件上:在<resultMap>标签里面使用<association>还是<collection>标签就可以。

所以:在学习MyBatis多表查询时其实就是在学习<association>标签和<collection>标签。其中如果一个实体类关联另一个实体类的一个对象使用<association>。如果一个实体类关联另一个实体类的List集合对象,需要使用<collection>。

所以分析的思路是:先分析需求->分析数据库设计对应关系->创建实体类->根据实体类关联属性类型决定使用哪个标签。

这两个标签根据编写的SQL,分为N+1查询和联合查询两种方式。两种方式优缺点:

  • N+1方式:

优点:SQL简单。支持延迟加载。

缺点:多做N次查询。

  • 联合查询方式:

优点:一次查询。

缺点:SQL相对复杂。不支持延迟加载。

MyBatis多表查询时一定需要使用<resultMap>标签,因为<association>标签和<collection>标签是<resultMap>的子标签。所以数据库设计时列名和实体类的属性名是否相同无所谓了,下面在设计数据库时按照数据库设计的命名规范进行设计。

案例:

  1. 数据库准备 tb_dept部门表 tb_customer客户表 tb_address地址表

create table tb_dept(
    dep_id int(11) primary key auto_increment COMMENT '部门主键',
    dep_name  varchar(32) COMMENT '部门名称',
    dept_addr varchar(255) COMMENT '部门地址'
);

insert into tb_dept value(DEFAULT,'教学部','无忧工业园');
insert into tb_dept value(DEFAULT,'行政部','无忧工业园');
insert into tb_dept value(DEFAULT,'财务部','无忧工业园');

create table tb_customer(
    id int(11) PRIMARY key auto_increment,
    name varchar(32) COMMENT '姓名',
    username varchar(32) COMMENT '登录名',
    password varchar(32) COMMENT '登录密码'
);

create table tb_address(
    id int(11) PRIMARY key auto_increment,
    province varchar(32) COMMENT '省',
    city varchar(32) COMMENT '市',
    address varchar(255) COMMENT '具体地址',
    customer_id int(11) REFERENCES tb_customer(id)
);

insert into tb_customer values (DEFAULT,'张三','zhangsan','123');
insert into tb_customer values (DEFAULT,'李四','李四','123');
insert into tb_customer values (DEFAULT,'王五','wangwu','123');

insert into tb_address values(DEFAULT,"广东","广州市","越秀区",1)
insert into tb_address values(DEFAULT,"广东","广州市","越秀区",1)
insert into tb_address values(DEFAULT,"广东","广州市","天河区",2)
insert into tb_address values(DEFAULT,"广东","广州市","天河区",2)
insert into tb_address values(DEFAULT,"广东","广州市","白云区",3)
insert into tb_address values(DEFAULT,"广东","广州市","白云区",3)
  1. Address实体类 没有在文档里面粘贴getter/setter和toString(),太占地方 需要读者自己编写(要加空构造器)

import java.io.Serializable;
import java.util.Objects;

public class Address implements Serializable {
    private Integer id;
    private String province;
    private String city;
    private String address;

    private Customer customer;
}
  1. Customer实体类 没有在文档里面粘贴getter/setter和toString(),太占地方 需要读者自己编写(要加空构造器)

import java.io.Serializable;
import java.util.List;
import java.util.Objects;

public class Customer implements Serializable {
    private Integer id;
    private String name;
    private String username;
    private String password;

    private List<Address> addressList;
    
}

案例实现功能:

  1. 查询全部地址,同时查询地址对应的客户数据

当存在调用和被调用关系时,按照正常编程习惯,都是先编写被调用方。

N+1次实现 当查询Customer表中N调数据时,需要编写1条查询全部的SQL,和N条根据外键列值作为另一张表主键查询条件的N条SQL语句。

被调用方 客户

创建接口com.bjsxt.mapper.CustomerMapper

package com.xu.mapper;

import com.xu.pojo.Customer;

import java.util.List;

/**
 * 客户访问接口
 */
public interface CustomerMapper {
    Customer selectAllById();
}

在包com.xu.mappers下创建CustomerMapper.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xu.mapper.CustomerMapper">

    <select id="selectById" resultType="Customer">
        select id,name,username,password from tb_customer where id =#{id}
    </select>

</mapper>

创建接口com.bjsxt.mapper.AddressMapper

import com.xu.pojo.Address;

import java.util.List;

/**
 * 地址数据访问接口
 */
public interface AddressMapper {
    List<Address> selectAll();
}

在包com.xu.mapper下创建.AddressMapper.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xu.mapper.AddressMapper">
    
    <resultMap id="addMap" type="Address">
        <id column="id" property="id"></id>
        <result column="province" property="province"/>
        <result column="city" property="city"/>
        <result column="address" property="address"/>
        <!--非集合类型的引用类型 customer,属性类型是Customer
            property -非集合类型引用类型属性名
            javaType -非集合类型引用类型的具体类型 可以是使用包名.类名 或者别名
            select - 这个属性的值用哪个SQL去查询 赋值规则是 namespace.select标签id
            column - 当前resultMap使用在哪一个select标签上,那么使用这个标签中的SQL查询结果的哪一个字段的值作为参数
                    调用select属性对应的SQL。
                    如果只需要一个参数,则直接写查询SQL中的字段名
                    如果select属性对应的SQL需要多个参数(包括一个),则使用语法{占位变量名:查询SQL的字段名} 类似json格式

        -->
        <association property="customer" javaType="Customer"
                     select="com.xu.mapper.CustomerMapper.selectById"
                     column="{id:customer_id}">
        </association>
    </resultMap>
    <select id="selectAll" resultType="addMap">
        select id,province,city,address,costomer_id from tb_address
    </select>

一次实现

接口com.bjsxt.mapper.AddressMapper 添加方法

   List<Address> selectAll2();

AddressMapper.xml配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xu.mapper.AddressMapper">

    <!--执行处理流程
        1.执行sql
        2.按照resultMap中的id和result子标签,封装Address类型对象,并给普通属性赋值
        3.按照association中的id和子标签 封装Customer类型对象,并给普通属性赋值
    -->

    <resultMap id="addMap1" type="Address">
        <id column="id" property="id"></id>
        <result column="province" property="province"/>
        <result column="city" property="city"/>
        <result column="address" property="address"/>
        <!-- 如果用于描述的非集合类型引用类型属性,且这个这个属性的值,是通过多表联合查询的到的结果
           配置时,不需要提供select和column属性,需要增加子标签.-->
        <association property="customer" javaType="Customer">
            <id column="cusId" property="id"></id>
            <result column="name" property="name"></result>
            <result column="username" property="username"></result>
            <result column="password" property="password"></result>
        </association>
    </resultMap>
    <!-- 一次查询,是使用关联查询实现。也就是多表联合查询实现。
        一条SQL查出一切需要的数据
       
    -->

    <select id="selectAll2" resultMap="">
        select addr.id,addr.province,addr.city,addr.address,cus.id as cusId,cus.name,cus.password from tb_address as addr left join tb_customer as cus on addr.customer_id = cus.id
    </select>

    
  
</mapper>
  1. 查询全部客户,同时查询客户对应的地址集合

一次查询实现

CustomerMapper接口添加方法

 List<Customer> selectAll2();

配置CustomerMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xu.mapper.CustomerMapper">
    
    <resultMap id="cusMap" type="Customer">
        <id column="cusId" property="id"></id>
        <result column="name" property="name"></result>
        <result column="username" property="username"></result>
        <result column="password" property="password"></result>
        
        <collection property="addressList" javaType="java.util.ArrayList" ofType="Address">
            <!-- 从数据库查询出来的每行数据对的哪个属性 -->
            <id column="id" property="id"></id>
            <result column="name" property="name"></result>
            <result column="address" property="address"></result>
        </collection>
    </resultMap>

    <select id="selectAll2" resultMap="cusMap1">
        select cus.id as cusId,cus.name,cus.username,cus.password,addr.id,addr.city,addr.address from
        tb_customer as cus left join tb_address as addr on cus.id = addr.customer_id
    </select>
</mapper>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MyBatis关联查询是指在查询数据库时,通过配置映射文件,将多个表之间的关联数据查询出来并进行组合。可以使用嵌套结果映射或嵌套查询来处理关联查询。 在嵌套结果映射中,可以使用\<resultMap>来定义映射关系,并使用\<association>来设置关联对象。例如,可以定义一个resultMap来映射Classes和Teacher表之间的关联关系,然后通过联表查询将两个表的数据关联起来。 另一种方式是使用嵌套查询,即在映射文件中通过\<select>标签设置嵌套查询语句来获取关联数据。通过联表查询获取到的数据可以作为嵌套查询的参数,从而获取到关联数据。 以上就是MyBatis关联查询的基本概念和使用方式。可以根据具体的需求选择合适的方式进行关联查询操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [SSM框架的学习与应用-Java EE企业级应用开发学习记录(第四天)Mybatis的关联映射和缓存机制](https://download.csdn.net/download/m0_53659738/88253127)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [mybatis关联查询](https://blog.csdn.net/faramita_of_mine/article/details/122202515)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值