Mybatis多表查询之一对多、多对一

简介: Mybatis多表查询之一对多、多对一

目录


前言

上次整理了单表的一些基本操作,现实工作可能会涉及复杂的多表查询,本文主要对Mybatis多表查询之一对多、多对一进行讲述。无论是一对多还是多对一,无非是涉及两个标签:collection和association,至于怎么去用和理解,后文会说明。每种查询都可以用两种方式去实现:按照查询嵌套处理(子查询)和按照结果嵌套处理(联表查询)。在进行操作前,需要把相关配置搞定,可以参考博主以往的博客。看之前需要对几个标签有所理解:

property:对象、成员变量属性的名称

column:数据库字段名称

javaType:对象属性的类型

ofType:集合中的泛型信息

association:一个复杂类型的关联

collection:一个复杂类型的集合

一、建立数据库

建立一个student表和teacher表,用外键将它们关联起来,一般公司出于性能和易维护性角度来说,不会使用外键去关联表,而是在业务层处理。

student表:

CREATE TABLE `student` (
  `id` int(10) NOT NULL,
  `name` varchar(30) DEFAULT NULL,
  `tid` int(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fktid` (`tid`),
  CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (1, '姚伟', 1);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (2, '谢帅阁', 3);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (3, '王小二', 2);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (4, '马小跳', 2);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (5, '巫妖王', 4);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (6, '范冰冰', 1);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (7, '迪丽热巴', 1);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (8, '李帅哥', 4);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (9, '老王哥', 1);

teacher表:

CREATE TABLE `teacher` (
  `id` int(10) NOT NULL,
  `name` varchar(30) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `teacher` (`id`, `name`) VALUES (1, '秦老师');
INSERT INTO `teacher` (`id`, `name`) VALUES (2, '谢老师');
INSERT INTO `teacher` (`id`, `name`) VALUES (3, '尧老师');
INSERT INTO `teacher` (`id`, `name`) VALUES (4, '王老师');

二、多对一查询

何为多对一?假设有一个班的学生,某节课给他们上课的有一个固定的老师,你可以说多个学生关联这个老师。

2.1 编写实体类

Teacher.java:

package com.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
    private int id;
    private String name;
    //学生需要关联一个老师
    private Teacher teacher;
}

Student.java:

package com.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
    private int id;
    private String name;
}

2.2 编写接口

这里定义查询所有学生信息及对应老师信息的方法,有子查询和按结果嵌套两种方法,返回的是list集合类型。

StudentMapper.java:

package com.dao;
import com.pojo.Student;
import java.util.List;
public interface StudentMapper {
    //子查询
    List<Student> getStudent();
    //按结果嵌套查询
    List<Student> getStudent2();
}

2.3 编写Mapper配置文件 (StudentMapper.xml

子查询:就是SQL里面的嵌套查询,我们现在有两张表,就需要查两次。由于是多个学生关联一个老师,所以这里用 association 标签,关联标签返回的是对象属性的类型(javaType)。我们首先要查询出所有的学生信息,因为学生实体类中除了变量属性还有对象属性(学生所关联的Teacher对象属性),变量属性可以很好地对应数据库的字段名,而对象属性需要用结果集映射。然后,根据查询出的学生tid,寻找对应的老师。因为映射之后,相应的tid已经有了,所以id=#{tid}括号里面的可以随意填写。

<mapper namespace="com.dao.StudentMapper">
    <select id="getStudent" resultMap="StudentTeacher">
        select *
        from mybatis.student;
    </select>
    <resultMap id="StudentTeacher" type="student">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
    </resultMap>
    <select id="getTeacher" resultType="teacher">
        select *
        from mybatis.teacher
        where id = #{tid}
    </select>

按结果嵌套查询:按结果嵌套查询就是SQL里面的联表查询,利用的是笛卡尔积将两张表关联,只需查一次,无论是效率方面还是理解层面上,按结果嵌套查询都要优于子查询,所以这里推荐使用第二种。可以很清楚地看出,按结果嵌套查询是先把查询完整语句给出,然后再对取别名的字段进行映射。对于对象属性的利用association进行字段对应。你可以这样理解,两张表都有name和id属性,如果不用association标签,两个name和id属性势必会冲突。


/

<select id="getStudent2" resultMap="StudentTeacher1">
        select s.id sid, s.name sname, t.name tname,t.id tid
        from mybatis.teacher t,
             mybatis.student s
        where s.tid = t.id
    </select>
    <resultMap id="StudentTeacher1" type="Student">
        <result property="name" column="sname"/>
        <result property="id" column="sid"/>
        <association property="teacher" javaType="Teacher">
            <result property="id" column="tid"/>
            <result property="name" column="tname"/>
        </association>
    </resultMap>


2.4 多对一查询结果

@Test
    public void test() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> list = mapper.getStudent();
        for (Student student : list) {
            System.out.println(student);
        }
        sqlSession.close();
    }

5a559f4849dcfcc72e74db96e4ed2188_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5YWo5p2R56ys5LqM5biF,size_20,color_FFFFFF,t_70,g_se,x_16.png

三、一对多查询

何为一对多?即一个老师可以给多个学生上课,这些学生可以组成一个集合,所以表示为一对多,并且用collection标签来表示。

3.1 编写实体类

Teacher.java:

package com.pojo;
import lombok.Data;
import java.util.List;
@Data
public class Teacher {
    private int id;
    private String name;
    //一个老师拥有多个学生
    private List<Student> students;
}

Student.java:

package com.pojo;
import lombok.Data;
@Data
public class Student {
    private int id;
    private String name;
    private int tid;
}

3.2 编写接口

这里先是利用子查询和按结果嵌套查询去获取所有的老师及对应的学生,然后通过id获取指定老师下的所有学生及老师的信息。

TeacherMapper.java:

package com.dao;
import com.pojo.Teacher;
import java.util.List;
public interface TeacherMapper {
    //获取所有的老师及对应的学生
    List<Teacher> getTeacher();
    List<Teacher> getTeacher2();
    //获取指定老师下所有的学生及老师的信息
    Teacher getTeacher3(int id);
}

3.3 编写Mapper配置文件 (TeacherMapper.xml

按结果嵌套查询:

<select id="getTeacher" resultMap="TeacherStudent">
        select t.id tid, t.name tname, s.name sname, s.id sid
        from mybatis.teacher t,
             mybatis.student s
        where t.id = s.tid
    </select>
    <!--javaType=""指定属性的类型!集合中的泛型信息我们用ofType来获取-->
    <resultMap id="TeacherStudent" type="Teacher">
        <result property="name" column="tname"/>
        <result property="id" column="tid"/>
        <collection property="students" ofType="Student">
            <result property="name" column="sname"/>
            <result property="id" column="sid"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>

子查询:

<select id="getTeacher2" resultMap="TeacherStudent2">
        select *
        from mybatis.teacher
    </select>
    <resultMap id="TeacherStudent2" type="Teacher">
        <result column="id" property="id"/>
        <result column="name" property="name"/>
        <collection property="students" javaType="Arraylist" ofType="Student" select="getStudent" column="id"/>
    </resultMap>
    <select id="getStudent" resultType="Student">
        select *
        from mybatis.student
        where tid = #{tid}
    </select>

按照指定id去查指定的老师,并得到这个老师下的所有学生(这里推荐使用按结果嵌套查询) :

<select id="getTeacher3" resultMap="TeacherStudent3">
        select s.id sid, s.name sname, t.id tid, t.name tname
        from mybatis.student s,
             mybatis.teacher t
        where s.tid = t.id
          and t.id = #{id}
    </select>
    <resultMap id="TeacherStudent3" type="Teacher">
        <result column="tid" property="id"/>
        <result column="tname" property="name"/>
        <collection property="students" ofType="Student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>

3.4 一对多查询结果

package com;
import com.dao.TeacherMapper;
import com.pojo.Teacher;
import com.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class MyTest {
    @Test
    public void test(){
        SqlSession sqlSession= MybatisUtils.getSqlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        List<Teacher> teacher = mapper.getTeacher();
        for (Teacher teachers : teacher) {
            System.out.println(teachers);
        }
        sqlSession.close();
    }
    @Test
    public void test1(){
        SqlSession sqlSession= MybatisUtils.getSqlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        List<Teacher> teacher = mapper.getTeacher2();
        for (Teacher teachers : teacher) {
            System.out.println(teachers);
        }
        sqlSession.close();
    }
    @Test
    public void test2(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacher3 = mapper.getTeacher3(4);
        System.out.println(teacher3);
        sqlSession.close();
    }
}

结果1:

结果2:

相关文章
|
3月前
|
SQL XML Java
mybatis复习04高级查询 一对多,多对一的映射处理,collection和association标签的使用
文章介绍了MyBatis中高级查询的一对多和多对一映射处理,包括创建数据库表、抽象对应的实体类、使用resultMap中的association和collection标签进行映射处理,以及如何实现级联查询和分步查询。此外,还补充了延迟加载的设置和用法。
mybatis复习04高级查询 一对多,多对一的映射处理,collection和association标签的使用
|
2月前
|
SQL XML Java
Mybatis中一对一和一对多的处理
这篇文章讲解了在Mybatis中如何处理一对一和一对多的关系映射,包括使用association和collection标签的具体方法。
57 1
|
7月前
|
SQL 缓存 Java
mybatis 一对多查询
mybatis 一对多查询
133 0
|
4月前
|
Java 数据库连接 mybatis
后端框架的学习----mybatis框架(9、多对一处理和一对多处理)
这篇文章介绍了在MyBatis框架中如何处理多对一和一对多的关联查询,通过定义`<resultMap>`和使用`<association>`与`<collection>`元素来实现对象间的关联映射。
|
6月前
|
Java 数据库连接 mybatis
Mybatis基于注解的一对一和一对多查询
Mybatis基于注解的一对一和一对多查询
|
6月前
|
SQL Java 数据库连接
Mybatis中一对多mapper配置
Mybatis中一对多mapper配置
|
7月前
|
Java 数据库连接 mybatis
mybatis的一对多
mybatis的一对多
|
7月前
|
XML SQL Java
mybatis的一对多,多对一,以及多对对的配置和使用
mybatis的一对多,多对一,以及多对对的配置和使用
44 2
|
7月前
|
存储 XML Java
mybatis使用内部类处理一对多类型数据2
mybatis使用内部类处理一对多类型数据2
79 0
|
2月前
|
Java 数据库连接 Maven
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和MyBatis Generator,使用逆向工程来自动生成Java代码,包括实体类、Mapper文件和Example文件,以提高开发效率。
152 2
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。