Mybatis多表查询

简介: 主要讲解了Mybatis的多表查询的思路和使用针对resultMap及其中的association及collection进行案例介绍

前言

数据库中的关系:一对一一对多多对多

理解为什么要有这些关系?

数据库是对现实世界的抽象。个人是数据库中一条横向的信息,如果社会所有人所有事,都无交集,那信息查询很简单,每次查一条就好了。那么应对复杂的社会关系,数据库就有了以上的这些关系

下面我通过 三个例子:实现Mybatis的多表查询 ,希望这篇文章对你在探索Mybatis多表查询时有帮助。


Tips如果你以前使用过多表查询,现在模糊了,看一下 “Mybatis针对多表查询提供哪些技术即可”;如果你第一次接触mybatis的多表查询,我建议你完整看完,并且自己去练习一下。

Mybatis针对多表查询提供哪些技术?

主要就是这个 resultMap

// totalStudent ID 标识对应下面
// type表示,这个信息最后是封装到student类中,而student类中可能包含其他类,(单类)使用association;(列表)使用collection
<resultMap id="totalStudent" type="student">
    // 查询到的student表的主键,id 表示一条数据的主键,对应数据库中的主键(规范)
    <id column="id" property="id"></id>
    // 查询到student表的student_name 封装到 student类中的studentName,result表示结果,本质上id和result作用一样,只是一个规范罢了
    // column对应着数据库的列名,property对应着实体类中的名称
    <result column="student_name" property="studentName"></result>
    
    // association 用于 一对一,多对一的情况,封装的是一个对象
    // property 表示student类中(包含的其他类)的名称,例如 Info infoo,填入infoo
    // javaType 表示该(其他类)的全类名或者别名,用于定位封装,例如 Info infoo,填入Info的全类名或者别名
    <association property="info" javaType="info">
        <id column="id" property="id"></id>
        <result column="info" property="info"></result>
    </association>
    
    // collection 用于 一对多的情况,封装的是一个集合
    // property 表示student类中(List<info> cyl)的名称,例如这里就该填cyl
    // ofType 表示该(List<info> cyl)的全类名或者别名,用于定位封装,例如这里就该填info的全类名或者别名
    <collection property="***" ofType="***">
        <id column="***" property="***"></id>
        <result column="***" property="***"></result>
    </collection>
</resultMap>

// totalStudent ID 标识对应上面
<select id="***" resultMap="totalStudent">
    
</select>

Question resultType 和 resultMap 区别

  • image.png
  • image.png

回答:

resultType :没有涉及到多表查询,查询的结果直接可以封装到对应的bean类型,在resultType中注明即可。

resultMap :最大的特征就是,要封装的类属性中含有其他的类对象,需要将结果封装到对应的类后,再注入到相应的属性中。

注意点 association 和 collection 使用注意事项

  • association使用 javaType 描述的是pojo的类型
  • collection使用 oftype 描述的是集合的类型

一对一 学籍信息

学生只能有一个学籍信息,通过学籍信息也只能查到对应的一个学生

示例目标 :

  1. 查询某个人具体的学籍信息
  2. 查询学籍信息对应的具体人员

数据库实现

erDiagram
Person }|--|{ info : search
  • Student表
CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `student_name` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
  `id_card` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `id_card` (`id_card`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin
  • Info表
CREATE TABLE `info` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `student_id_card` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
  `info` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `student_id_card` (`student_id_card`),
  CONSTRAINT `info_ibfk_1` FOREIGN KEY (`student_id_card`) REFERENCES `student` (`id_card`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin

Mybatis实现一对一查询

association:一个学生只有一个学籍信息,一个学籍信息只对应一个学生

Pojo

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Student {
  private Integer id;
  private String studentName;
  private String idCard;
  // 查询每个学生时,顺带知道他的学籍信息
  private Info info;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Info {
  private Integer id;
  private String studentIdCard;
  private String info;
  // 查询每个学籍信息时,知道该学籍信息是属于哪个学生的
  private Student student;

  @Override
  public String toString() {
    return "Info{" +
            "id=" + id +
            ", info='" + info + ''' +
            '}';
  }
}

Mapper Interface

public interface StudentMapper {
    // 查询所有学生信息
    public List<Student> getAllStudent();
    // 查询某个学生信息
    public Student selectById(@Param("id") Integer id);
}
public interface InfoMapper {
    // 通过身份ID在学籍信息中查询对应人员信息
    public Info selectByIdCard(@Param("id") String idCard);
}

StudentMapper.xml

    <resultMap id="totalStudent" type="student">
        <id column="id" property="id"></id>
        <result column="student_name" property="studentName"></result>
        <result column="id_card" property="idCard"></result>

        <association property="info" javaType="info">
            <id column="id" property="id"></id>
            <result column="info" property="info"></result>
        </association>
    </resultMap>
    
    <!--select * from student s,info i  WHERE s.id_card = i.student_id_card;-->
    <select id="getAllStudent" resultMap="totalStudent">
        select * from student s,info i  WHERE s.id_card = i.student_id_card;
    </select>

    <!--select * from student s,info i  WHERE s.id_card = i.student_id_card AND s.id_card='330127199808110000';-->
    <select id="selectById" resultMap="totalStudent">
        select * from student s,info i  WHERE s.id_card = i.student_id_card AND s.id_card=#{id};
    </select>
  • getAllStudent 测试结果:
==>  Preparing: select * from student s,info i WHERE s.id_card = i.student_id_card;
==> Parameters: 
<==    Columns: id, student_name, id_card, id, student_id_card, info
<==        Row: 1, chengyunlai, 330127199808110000, 1, 330127199808110000, 研究生
<==        Row: 2, xuhuajie, 330110199702230000, 2, 330110199702230000, 研究生
<==      Total: 2
{"id":1,"idCard":"330127199808110000","info":{"id":1,"info":"研究生"},"studentName":"chengyunlai"}
{"id":2,"idCard":"330110199702230000","info":{"id":2,"info":"研究生"},"studentName":"xuhuajie"}
  • selectById 测试结果:
==>  Preparing: select * from student s,info i WHERE s.id_card = i.student_id_card AND s.id_card=?;
==> Parameters: 330127199808110000(String)
<==    Columns: id, student_name, id_card, id, student_id_card, info
<==        Row: 1, chengyunlai, 330127199808110000, 1, 330127199808110000, 研究生
<==      Total: 1
{"id":1,"idCard":"330127199808110000","info":{"id":1,"info":"研究生"},"studentName":"chengyunlai"}

实验结果 :将学籍信息封装在了学生类中,实现了通过学生查询到相关学籍信息

InfoMapper.xml

<resultMap id="information" type="info">
    <id column="id" property="id"></id>
    <result column="student_id_card" property="studentIdCard"></result>
    <result column="info" property="info"></result>

    <association property="student" javaType="student">
        <id column="id" property="id"></id>
        <result column="student_name" property="studentName"></result>
        <result column="id_card" property="idCard"></result>
    </association>
</resultMap>
<!--select * from info i,student s where i.student_id_card = s.id_card AND i.student_id_card='330127199808110000';-->
<select id="selectByIdCard" resultMap="information">
    select * from info i,student s where i.student_id_card = s.id_card AND i.student_id_card=#{id};
</select>
  • selectByIdCard 测试结果:
==>  Preparing: select * from info i,student s where i.student_id_card = s.id_card AND i.student_id_card=?;
==> Parameters: 330127199808110000(String)
<==    Columns: id, student_id_card, info, id, student_name, id_card
<==        Row: 1, 330127199808110000, 研究生, 1, chengyunlai, 330127199808110000
<==      Total: 1
{"id":1,"info":"研究生","student":{"id":1,"idCard":"330127199808110000","studentName":"chengyunlai"},"studentIdCard":"330127199808110000"}

实验结果 :通过身份Id实现了查询学籍信息及对应的人员信息


一对多 家有宠物

我喜欢小狗,我可以养很多小狗,但小狗认主人只能有一个,要负责任!

示例目标 :

  1. 查询某个人有哪些宠物
  2. 查询某个宠物对应的主人是谁

数据库实现

erDiagram
Person }|--|{ pet1 : hava
Person }|--|{ pet2 : hava
  • person表
CREATE TABLE `person` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `person_name` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_bin
  • pet表
CREATE TABLE `pet` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `pet_name` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
  `person_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `person_id` (`person_id`),
  CONSTRAINT `pet_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `person` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin

Mybatis实现一对多查询

collection 一个人有很多宠物,查询人的时候多个宠物封装用collection

association 一个宠物只认一个主人,反过来又是一个:一对一的问题

Pojo

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Person {
  private Integer id;
  private String personName;
  // 注意看 一对多,这里是一个集合,这很关键,封装需要用collection
  private List<Pet> pet;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Pet {
  private Integer id;
  private String petName;
  private long personId;
}

Mapper Interface

public interface PersonMapper {
    // 遍历所有人员及其养的所有宠物信息
    public List<Person> getPersonAndPet();
}
public interface PetMapper {
    // 通过宠物姓名查询信息,级联查询该宠物是属于哪个主人
    public Pet getPetInfoByName(@Param("name") String petName);
}

PersonMapper.xml

<mapper namespace="top.itifrd.mapper.PersonMapper">
    <resultMap id="allPerson" type="person">
        <id column="id" property="id"></id>
        <result column="person_name" property="personName"></result>
        <collection property="pet" ofType="pet">
            <id column="pt.id" property="id"></id>
            <result column="pet_name" property="petName"></result>
            <result column="person_id" property="personId"></result>
        </collection>
    </resultMap>
    
    <select id="getPersonAndPet" resultMap="allPerson">
        select * from person ps,pet pt where ps.id = pt.person_id;
    </select>
  • getPersonAndPet测试结果:
==>  Preparing: select * from person ps,pet pt where ps.id = pt.person_id;
==> Parameters: 
<==    Columns: id, person_name, id, pet_name, person_id
<==        Row: 1, chengyunlai, 1, 小黑, 1
<==        Row: 1, chengyunlai, 2, 小哈, 1
<==      Total: 2
{"id":1,"personName":"chengyunlai","pet":[{"personId":1,"petName":"小黑"},{"personId":1,"petName":"小哈"}]}

PerMapper.xml

<mapper namespace="top.itifrd.mapper.PetMapper">
    <resultMap id="allPet" type="pet">
        <id column="id" property="id"></id>
        <result column="pet_name" property="petName"></result>
        <result column="pt.person_id" property="personId"></result>

        <association property="person" javaType="person">
            <id column="id" property="id"></id>
            <result column="person_name" property="personName"></result>
        </association>
    </resultMap>

    <select id="getPetInfoByName" resultMap="allPet">
        select * from pet pt, person ps where pt.person_id = ps.id and pt.pet_name = #{name};
    </select>
  • getPetInfoByName测试结果:
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4c15e7fd]
==>  Preparing: select * from pet pt, person ps where pt.person_id = ps.id and pt.pet_name = ?;
==> Parameters: 小黑(String)
<==    Columns: id, pet_name, person_id, id, person_name
<==        Row: 1, 小黑, 1, 1, chengyunlai
<==      Total: 1
Pet(id=1, petName=小黑, personId=0, person=Person(id=1, personName=chengyunlai, pet=null))

分析 一对一一对多

在XML操作上这两者并没有多少本质的区别,可以说是一模一样。

其本质其实是在数据库的构建上,在构建中体现数据表之间的关系,这个很重要


多对多 角色表

我可能是个 程序员摄影师美食达人,而我也不是唯一的程序员,摄影师,美食达人,我的朋友可能也是

待更新

目录
相关文章
|
5月前
|
Java 数据库连接 数据库
MyBatis之多表查询
MyBatis之多表查询
|
7月前
|
SQL XML Java
Mybatis:SQL注入问题 like模糊查询 多表查询 动态SQL
Mybatis:SQL注入问题 like模糊查询 多表查询 动态SQL
104 0
|
2月前
|
XML Java 数据库连接
【MyBatis】1、MyBatis 核心配置文件、多表查询、实体映射文件 ......
【MyBatis】1、MyBatis 核心配置文件、多表查询、实体映射文件 ......
91 0
|
4月前
|
SQL Java 数据库连接
Mybatis如何实现多表查询
Mybatis如何实现多表查询
|
7月前
|
XML Java 数据库连接
“MyBatis中的关联关系配置与多表查询“
“MyBatis中的关联关系配置与多表查询“
27 0
|
8月前
|
SQL XML Java
Mybatis的多表查询操作 2
Mybatis的多表查询操作
55 1
|
8月前
|
XML Java 数据库连接
Mybatis的多表查询操作 1
Mybatis的多表查询操作
43 1
|
9月前
|
SQL Java 数据库连接
|
10月前
|
SQL Java 数据库连接
Mybatis如何实现多表查询?
MyBatis是一个Java持久层框架,它提供了多种方式来实现多表查询。
710 0
|
10月前
|
SQL XML Java
如何在 MyBatis 中进行多表查询以及注解开发?
如何在 MyBatis 中进行多表查询以及注解开发?
249 0