MyBatis 一对多、多对一的处理~

1、多对一处理


1.1、打个比方

image-20200726203354720

比如:多个学生对应一个老师

  • 对于学生,关联,多个学生关联一个老师【多对一】
  • 对于老师,集合,一个老师有多个学生【一对多】

1.2、实例环境搭建

  1. 搭建数据库表
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, '秦老师');

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', '小红', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');

我们画出两个表对应的关系,从学生这边看,是多对一的关系,student表的tid是外键对应teacher表的id

image-20200726204610911
  1. 导入lombok依赖,下载lombok插件
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
    <scope>provided</scope>
</dependency>
  1. 新建实体类Student和Teacher

    学生的第三个字段tid对应一个老师,所以学生的实体类Student中第三个属性为Teacher类型

package pojo;

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

@data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
    private int id;
    private String name;
}
  1. 创建StudentMapper和TeacherMapper接口
package mapper;

public interface StudentMapper {

}
package mapper;

import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import pojo.Teacher;

public interface TeacherMapper {

}
  1. 创建StudentMapper.xml和Teacher.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.StudentMapper">

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

</mapper>
  1. MyBatis核心配置文件中绑定Mapper接口
<mappers>
    <mapper class="mapper.TeacherMapper"/>
    <mapper class="mapper.StudentMapper"/>
</mappers>
  1. 编写测试类
public class MyTest {

}

1.3、目标:查询所有的学生信息以及对应的老师信息


方式一:查询嵌套

StudentMapper接口中添加getStudent方法,用来查询所有学生

public List<Student> getStudent();

StudentMapper.xml进行配置

  1. 首先用 getStudent方法 查询所有的学生信息
  2. 再利用resultMap进行查询嵌套映射
    • Student实体类中的id属性 ==> 数据库student表中的id字段
    • Student实体类中的name属性 ==> 数据库student表中的name字段
    • Student实体类中的teacher属性 ==> 数据库student表中的tid字段
      • 利用select标签实现嵌套查询,绑定id为getStudent的查询语句,根据查询出来的学生的tid,寻找对应的老师!
<!--查询嵌套映射-->
<resultMap id="studentTeacher" type="pojo.Student">
    <result column="id" property="id"/>
    <result column="name" property="name"/>
    <!--复杂的属性,我们需要单独处理   对象:association   集合:coLLection-->
    <association column="tid" property="teacher" javaType="pojo.Teacher" select="getTeacher"/>
</resultMap>    

<select id="getStudent" resultMap="studentTeacher">
    select * from student
</select>

<select id="getTeacher" resultType="pojo.Teacher">
    select * from teacher where id = #{id}
</select>

测试类中添加测试方法

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

方式二:结果嵌套

StudentMapper.xml进行配置

  1. 首先用 getStudent2方法 条件查询
    • 查询学生的id,别名sid
    • 查询学生的name,别名sname
    • 查询老师的name,别名tname
    • 条件为 学生的tid=老师的id
  2. 利用resultMap进行结果嵌套映射
    • Student实体类中的id属性(sid) ==> 数据库student表中的id字段
    • Student实体类中的name属性(sname) ==> 数据student库表中的name字段
    • Student实体类中的teacher属性嵌套映射,由于是一个Teacher对象,使用association标签,且利用javaType指定java类型为Teacher
      • 对该Teacher对象再次进行映射
        • Teacher实体类中的name属性(tname) ==> 数据库teacher表中的name字段
<select id="getStudent2" resultMap="studentTeacher2">
    select s.id sid,s.name sname,t.name tname
    from student s,teacher t
    where s.tid=t.id
</select>
<resultMap id="studentTeacher2" type="pojo.Student">
    <result column="sid" property="id"/>
    <result column="sname" property="name"/>
    <association property="teacher" javaType="pojo.Teacher">
        <result column="tname" property="name"/>
    </association>
</resultMap>

测试类中添加测试方法

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


2、一对多处理

对于老师,集合,一个老师有多个学生【一对多】

同上搭建环境,不同之处

实体类

  • 老师的第二个字段id对应多个学生,所以老师的实体类Teacher中第二个属性为Student的集合
package pojo;

@data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private int id;
    private String name;
    private int tid;
}
package pojo;

@data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
    private int id;
    private String name;
    //一个老师有多个学生
    private List<Student> students;
}

2.1、目标:获取指定老师下的所有学生及老师的信息


方式一:结果嵌套

TeacherMapper接口中添加getTeacher方法,用来获取指定老师下的所有学生及老师的信息

//获取指定老师下的所有学生及老师的信息
Teacher getTeacher(@Param("tid") int id);

TeacherMapper.xml进行配置

  1. 首先用 getTeacer方法 根据指定的老师id条件查询
    • 查询学生的id,别名sid
    • 查询学生的name,别名sname
    • 查询老师的name,别名tname
    • 查询老师的id,别名tid
    • 条件为 学生的tid=老师的id
  2. 利用resultMap进行结果嵌套映射
    • Teacher实体类中的id属性(tid) ==> 数据库teacher表中的id字段
    • Teacher实体类中的name属性(tname) ==> 数据库teacher表中的name字段
    • Teacher实体类中的student集合属性嵌套映射,由于是Student集合,所以使用collection标签,并且利用oftype指定集合的泛型类型
      • 对该Student集合再进行映射
        • Student实体类中的id属性(sid) ==> 数据库student表中的id字段
        • Student实体类中的name属性(sname) ==> 数据student库表中的name字段
        • Student实体类中的tid属性 ==> 数据student库表中的tid字段
<!--结果嵌套映射-->
	<select id="getTeacher" resultMap="teacherStudent">
        select s.id sid,s.name sname,t.name tname,t.id tid
        from student s,teacher t
        where s.tid=t.id and t.id=#{tid}
    </select>

    <resultMap id="teacherStudent" type="pojo.Teacher">
        <result column="tid" property="id"/>
        <result column="tname" property="name"/>
        <!--
            javaType:指定属性的类型
            集合中的泛型信息,用oftype获取
		-->
        <collection property="students" ofType="pojo.Student">
            <result column="sid" property="id"/>
            <result column="sname" property="name"/>
            <result column="tid" property="tid"/>
        </collection>
    </resultMap>

测试类中添加测试方法

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

得到结果
image-20200727162310840

方式二:查询嵌套

TeacherMapper.xml进行配置

  1. 首先用 getTeacher2方法 查询所有的老师信息
  2. 利用resultMap进行查询嵌套映射
    • Teacher实体类中的id属性 ==> 数据库teacher表中的id字段
    • Teacher实体类中的name属性 ==> 数据库teacher表中的name字段
    • Teacher实体类中的student集合属性 ==> 数据库teacher表中的id字段
      • 利用select标签实现嵌套查询,绑定id为getStudentByTeacherID的查询语句,根据查询出来的老师的id,寻找对应的学生!
<select id="getTeacher2" resultMap="teacherStudent2">
    select * from teacher
</select>

<!--结果映射-->
<resultMap id="teacherStudent2" type="pojo.Teacher">
    <collection property="students" javaType="ArrayList" ofType="Student"
                select="getStudentByTeacherID" column="id"/>
</resultMap>

<select id="getStudentByTeacherID" resultType="pojo.Student">
    select * from student where tid=#{tid};
</select>

测试类中添加测试方法

@Test
public void getTeacher2() {
    SqlSession sqlSession = MyBatisUtils.getSqlSession();
    TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
    Teacher teacher2 = mapper.getTeacher2(1);
    System.out.println(teacher2);
    sqlSession.close();
}

3、小结

  1. 关联association 【多对一】
  2. 集合collection 【一对多】
  3. javaTypeofType
    • javaType用来指定实体类中属性的类型
    • ofType用来指定映射到集合中的pojo类型,泛型的约束类型

4、注意点

  1. 保证SQL的可读性,尽量保证通俗易懂
  2. 注意一对多和多对一中,属性和字段的问题
  3. 问题不好排查的情况下,建议使用日志排错

猜你喜欢

转载自blog.csdn.net/qq_45173404/article/details/107672660