多表查询是在企业中必不可少的,无论多么简单的项目里都会出现多表查询操作。因为只要是关系型数据库,在设计表时都需要按照范式进行设计,为了减少数据冗余,都会拆成多个表。当需要表中数据时,在进行联合查询。
在MySQL学习时,知道表之间关系分为:一对一、一对多、多对多。这三种关系又细分为单向和双向。如果学习的是Hibernate框架,必须要严格区分开表之间的关系,然后才能使用Hibernate框架。但是在MyBatis框架中只有两种情况:当前表对应另外表是一行数据还是多行数据。转换到实体类上:当前实体类包含其他实体类一个对象还是多个对象。再转换到MyBatis的映射文件上:在
所以:在学习MyBatis多表查询时其实就是在学习
所以分析的思路是:先分析需求->分析数据库设计对应关系->创建实体类->根据实体类关联属性类型决定使用哪个标签。
这两个标签根据编写的SQL,分为N+1查询和联合查询两种方式。两种方式优缺点:
N+1方式:
优点:SQL简单。支持延迟加载。
缺点:多做N次查询。
联合查询方式:
优点:一次查询。
缺点:SQL相对复杂。不支持延迟加载。
MyBatis多表查询时一定需要使用
案例:
数据库准备 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)
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;
}
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 addressList;
}
案例实现功能:
查询全部地址,同时查询地址对应的客户数据
当存在调用和被调用关系时,按照正常编程习惯,都是先编写被调用方。
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文件
创建接口com.bjsxt.mapper.AddressMapper
import com.xu.pojo.Address;
import java.util.List;
/**
* 地址数据访问接口
*/
public interface AddressMapper {
List selectAll();
}
在包com.xu.mapper下创建.AddressMapper.xml文件
一次实现
接口com.bjsxt.mapper.AddressMapper 添加方法
List selectAll2();
AddressMapper.xml配置
查询全部客户,同时查询客户对应的地址集合
一次查询实现
CustomerMapper接口添加方法
List selectAll2();
配置CustomerMapper.xml