MyBatis笔记(五)

111 阅读3分钟

1. 多对一

什么是多对一呢?

  • 多个学生对应一个老师

1.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');

image-20210412093855997

1.2 搭建测试环境

  1. 编写实体类POJO

    public class Teacher {
        private int id;
        private String name;
        
        // 无参构造
        // 有参构造
        // get、set方法
        // toString方法
    }
    
    public class Student {
        private int id;
        private String name;
        //多个学生可以是同一个老师,即多对一
        private Teacher teacher;
        
        // 无参构造
        // 有参构造
        // get、set方法
        // toString方法
    }
    
  2. 编写实体类对应的Mapper接口

    public interface StudentMapper {
    }
    
    public interface TeacherMapper {
    }
    
  3. 编写接口对应的mapper.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="top.linzeliang.mapper.StudentMapper">
     
    </mapper>
    
    <?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="top.linzeliang.mapper.TeacherMapper">
     
    </mapper>
    

1.3 按查询嵌套处理

  1. 给StudentMapper增加方法

    //获取所有学生及对应老师的信息
    public List<Student> getStudents();
    
  2. 编写对应的Mapper文件

    <!--    需求:获取所有学生及对应老师的信息        思路:            1. 获取所有学生的信息            2. 根据获取的学生信息的老师ID->获取该老师的信息            3. 思考问题,这样学生的结果集中应该包含老师,该如何处理呢,数据库中我们一般使用关联查询?                1. 做一个结果集映射:StudentTeacher                2. StudentTeacher结果集的类型为 Student                3. 学生中老师的属性为teacher,对应数据库中为tid。                   多个 [1,...)学生关联一个老师=> 一对一,一对多                4. 查看官网找到:association – 一个复杂类型的关联;使用它来处理关联查询--><select id="getStudents" resultMap="StudentMap">    select *    from student;</select><resultMap id="StudentMap" type="student">    <association property="teacher" column="tid" javaType="teacher" select="getTeacher"/></resultMap><!--        这里传递过来的id,只有一个属性的时候,下面可以写任何值        association中column多参数配置:            column="{key=value,key=value}"            其实就是键值对的形式,key是传给下个sql的取值名称,value是片段一中sql查询的字段名。--><select id="getTeacher" resultType="Teacher">    select *    from teacher    where id = #{tid};</select>
    
  3. 进行测试

1.4 按结果嵌套处理

个人认为这种容易理解一些

  1. 接口方法编写

    //获取所有学生及对应老师的信息public List<Student> getStudents(); 
    
  2. 编写对应的mapper配置文件

    <select id="getStudents" resultMap="StudentMap">    select t1.id id, t1.name sname, t2.id tid, t2.name tname    from student t1,    teacher t2    where t1.tid = t2.id;</select><resultMap id="StudentMap" type="student">    <id property="id" column="id"/>    <result property="name" column="sname"/>    <association property="teacher" javaType="Teacher">        <id property="id" column="tid"/>        <result property="name" column="tname"/>    </association></resultMap>
    
  3. 进行测试

2. 一对多

  • 一个老师对应多个学生

2.1 搭建测试环境

  • 实体类的编写

    public class Student {    private int id;    private String name;    private int tid;        // 无参构造    // 有参构造    // get、set方法    // toString方法}
    
    public class Teacher {    private int id;    private String name;    //一个老师多个学生    private List<Student> students;        // 无参构造    // 有参构造    // get、set方法    // toString方法}
    

2.2 按查询嵌套处理

  1. TeacherMapper接口编写方法

    //获取指定老师,及老师下的所有学生public Teacher getTeacher(int id);
    
  2. 编写接口对应的Mapper配置文件(多了ofType的这个属性)

    <select id="getTeacher" resultMap="TeacherMap">    select *    from teacher    where id = #{id};</select><resultMap id="TeacherMap" type="Teacher">    <id property="id" column="id"/>    <result property="name" column="name"/>    <!-- column是一对多的外键 , 写的是一的主键的列名 -->    <collection property="students" column="id" javaType="ArrayList" ofType="Student" select="getStudent"/></resultMap><select id="getStudent" resultType="Student">    select *    from student    where tid = #{id}</select>
    
  3. 进行测试

2.3 按结果嵌套处理

  1. TeacherMapper编写方法

    //获取指定老师,及老师下的所有学生public Teacher getTeacher(int id);
    
  2. 编写接口对应的Mapper配置文件

    <select id="getTeacher" resultMap="TeacherMap">    select t1.id tid, t1.name tname, t2.id sid, t2.name sname    from teacher t1,    student t2    where t1.id = t2.tid    and t1.id = #{id};</select><resultMap id="TeacherMap" type="Teacher">    <id property="id" column="tid"/>    <result property="name" column="tname"/>    <collection property="students" ofType="Student">        <id property="id" column="sid"/>        <result property="name" column="sname"/>        <result property="tid" column="tid"/>    </collection></resultMap>
    
  3. 进行测试

3. ResultMap总结

  • 如果属性是JavaBean对象,则使用关联(association)
  • 如果属性是集合,则使用集合(collection)
  • 则association是用于一对一和多对一;collecion适用于一对多的关系
  • javaType和ofType都是用于指定对象类型的
    • javaType是用来指定pojo中属性的类型
    • ofType指的是映射到list集合属性中的pojo的类型