Bootstrap

6.2 、MyBatis 高级映射(resultMap 标签多表联查 , 一对多,多对一关系)



一、创建表结构,添加数据,实现表中数据的关联关系


  • 数据的关联关系:

    • 一个班级中,有多名学生,一个班主任以及其他很多科任教师

      • 对于学生而言,多个学生,关联一个班主任,每个学生都和班主任有着关联关系 --【多对一

      • 班级中,有一名学生上课睡觉,被班主任抓个正着,拎出来训话 --【一对一

      • 对于班主任而言,一个班主任管理着一个班级,而班级中有很多学生 --【一对多

      • 一个班级中的每天都有不同的课程,不同的课程对应不同的教师 --【多对多


  • 表结构搭建
    -- 创建教师表
    CREATE TABLE IF NOT EXISTS `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 IF NOT EXISTS `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),(2, '龙大宇', 1),(3, '姬大德', 1),(4, '石昊', 1),(5, '叶凡', 1);
    
    



二、 association 标签:用于一对一、多对一场景使用


  • association 标签属性:

    • property :配置实体类属性名

    • javaType :指定封装结果的类型。当使用 select 属性时,无需指定关联的类型,结果会直接封装到调用的查询语句中

    • column :配置数据库列名,搭配 select 属性使用,从第一条 SQL 中获取当前指定字段的内容,在将该内容传入 select 属性调用的 SQL 中

    • select :使用另一个select查询封装的结果。当使用该属性时,无需配置实体类与数据库之间的映射关系

  • association 标签的子标签:< id >< result >, 作用和 resultMap 标签的子标签一致



1、实现一对一,多对一关系结果集映射

       实现联表查询的方式有两种,一种是按照查询嵌套处理,一种是按照结果嵌套处理。通常来讲按照结果嵌套处理比较灵活,代码看起来也更加简洁。

1.1 按照查询嵌套处理

       该方式的执行流程:先执行第一个被调用的 < select > 标签语句,查询出结果后通过 < association > 标签的 column 获取结果中指定字段的值,在通过 select 调用第二个 < select > 标签语句 ,将 column 获取到的值传入该标签语句中,实现类似于子查询的操作,最后将第一个被调用的标签语句查询出的结果封装到 < resultMap > 的 type 属性当中,将第二个被调用的标签语句封装到 < association > 标签的 property 所指定的实体类属性当中,以此来实现结果集的映射。



  • 根据表创建对应的实体类

    • 创建 Student 实体

      @Alias("Student")  // 引用 mybatis-config.xml 中的实体类路径别名,这样再次引用时候直接引用别名就可以找到全路径了
      @Data  // 自动生成 get()、set()等方法
      public class Student {
      
          private Integer id;
          private String name;
          private String tid;
      
          // 关联教师实体,形成一对一,多对一的关联关系,将查询结果封装到该属性中
          private Teacher teacher;
      }
      
    • 创建 Teacher 实体

      @Data
      @Alias("Teacher")
      public class Teacher {
      
          private Integer id;
          private String name;
      }
      
    • 创建 StudentMapper

      public interface StudentMapper {
      
          List<Student> getStudent();
      }
      
    • 创建 XML

       	<select id="getStudent" resultMap="StudentMap">
              select * from student
          </select>
      	
          <resultMap id="StudentMap" type="Student">
              <result column="id" property="id"/>
              <result column="name" property="name"/>
      
              <!-- 查询完第一条查询SQL之后,通过association标签的column属性获取对应字段的值,将该值传入select属性所指定的查询SQL中,
              根据条件查询完之后将结果封装到property属性所指定的实体bean的属性中。  -->
              <association property="teacher" column="tid" select="getTeacher"/>
          </resultMap>
      
          <select id="getTeacher" resultType="Teacher">
              select * from teacher where id = #{tid}
          </select>
      
    • 代码运行结果
      在这里插入图片描述




1.2 按照结果嵌套处理(推荐)

       直接使用多表联查的形式去查询数据,通过 result 标签的属性将 SQL 语句中的字段和实体类形成映射关系,再通过 association 标签的 property 属性将 Teacher 实体中的 name 属性与 Student 实体的 teacher 属性值形成映射,以此来完成返回值映射。
  • 实体类不变,StudentMapper 接口中新增查询方法

    public interface StudentMapper {
    
        List<Student> getStudent();
    
        List<Student> getStudentAndTeacher();
    
    }
    
  • XML

    <resultMap id="StudentAndTeacher" type="Student">
            <result property="id" column="id"/>
            <result property="name" column="name"/>
    
            <!-- 将查询结果映射到 Teacher 实体类中 -->
            <association property="teacher" javaType="Teacher">
                <result property="name" column="name"/>
            </association>
        </resultMap>
    
        <select id="getStudentAndTeacher" resultMap="StudentAndTeacher">
            select   s.id as 学生编号, s.name as 学生姓名, s.tid as 班级编号, t.id as 教师编号,t.name as 教师姓名
    	        from student s,
    	             teacher t
    	        where s.tid = t.id
        </select>
    
  • 运行结果:
    在这里插入图片描述




三、 collection 标签:用于一对多、多对多场景使用(实体里放集合)

  • collection 标签属性:

    • property :实体类属性名

    • select :使用另一个select查询封装的结果。当使用该属性时,便不需要在配置实体类与数据库之间的映射关系了

    • column :为数据库中的列名,与select配合使用

    • ofType :指定集合中的泛型信息

  • collection 标签的子标签:< id >,< result >, 作用和 resultMap 标签的子标签一致


1、实现一对多,多对多关系结果集映射


1.1 按照查询嵌套处理

       该方式的执行流程和 association 大致相同,区别为,association 是通过学生共有的班级编号匹配班主任的教师编号,是多对一的关系。而 collection 是通过教师编号去匹配班级编号相同的学生,是一对多关系。

  • 根据表创建对应的实体类

    • 创建 Student 实体

      @Alias("Student")  
      @Data  
      public class Student {
      
          private Integer id;
          private String name;
          private String tid;
      }
      
    • 创建 Teacher 实体

      @Data
      @Alias("Teacher")
      public class Teacher {
      
          private Integer id;
          private String name;
          
          // 实现老师对应学生的 一对多关联关系
          private List<Student> student;
      }
      
    • 创建 TeacherMapper

      public interface TeacherMapper {
      
         //通过教师编号查询与之关联的学生
         List<Teacher> getManyToOne(int id);
      }
      
    • 创建 XML

      <select id="getManyToOne" resultMap="getManyToOne">
          select * from teacher where id = #{id}
      </select>
      
      <resultMap id="getManyToOne" type="Teacher">
          <result property="id" column="id"/>
          <result property="name" column="name"/>
          <collection property="student" javaType="ArrayList" select="getStudent" column="id"/>
      </resultMap>
      
      <select id="getStudent" resultType="Student">
          select * from student where tid = #{id}
      </select>
      
    • 代码运行结果
      在这里插入图片描述




1.2 按照结果嵌套处理(推荐)

  • 实体类不变,TeacherMapper 接口中新增查询方法

    public interface TeacherMapper {
    
        List<Teacher> getManyToOne(int id);
    
        List<Teacher> getManyToOne2(int id);
    }
    
  • XML

       <resultMap id="getManyToOne2" type="Teacher">
            <result property="id" column="id"/>
            <result property="name" column="name"/>
            <collection property="student" ofType="Student">
                <result column="id" property="id"/>
                <result column="name" property="name"/>
                <result column="tid" property="tid"/>
            </collection>
        </resultMap>
    
        <select id="getManyToOne2" resultMap="getManyToOne2">
            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>
    
  • 运行结果:
    在这里插入图片描述



;