• Mybatis 08


    8.1 多对一 和 一对多


    在这里插入图片描述

    • 多个学生,对应一个老师
    • 对于学生来说,多个学生可能同时关联一个老师。
    • 对于老师而言,一个老师 教了很多的学生。类似于一个老师集合了很多学生。

    在结果映射 resultMap 中,associationcoLiction 是搭建 复杂查询的关键 标签。

    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=utf8INSERT 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');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

    • 查询所有的学生信息,一级对应的老师的信息。

    正常的 SQL:select s.id,s.name,t.name from student as s inner join teacher as t where s.tid = t.id;

    当然 我们也可以 用 下面这种 多此一举的子查询。

    select s.id,s.name,t.name as 老师 from student s inner join teacher t where s.tid = (select id from teacher);

    但实际上,我们 在使用 mybatis 的时候,目前来看。无论是 注解的方式,还是 select 标签的方式,都是无法直接实现的。因为 我们 能够提供的返回类型只能是 一个!而 注解 只能做 简单的 SQL 语句处理。

    那么我们就要学习一个 resultMap 里 两个 新的 子标签了。associationcoLiction


    8.1.1 association 多对一

    association 多对一,指的是 多个元素,关联一个元素,或者说 多个 对象 同时关联了一个 对象!

    这个时候我们通常采取 两种方式:resultMap 子查询resultMap 结果关联

    比如说 你查询的 学生表 里面 现在有一个 tid,我们可以 本来是 可以 通过 tid 查询到 教师信息,完成目标的。但我们 无法 像 SQL 那样灵活方便。那我们 就必须要 对 最终的结果集进行分析了。

    最终的结果集是 学生的 id 和 name,教师的 name。也就是说 我们 最终的结果集 是 没有 tid 的。

    1. resultMap 子查询

    首先,肯定是要 提供两个表的查询的。
    select * from teacher where id = #{tid} 只有查到了 teacher 对象,才能够 知道 teacher 的 name。而我们 肯定是 通过 查询到的 tid 找到 这个 teacher 对象的。

    select * from student 然后,我们 查 student 就正常查就行,因为最后处理 是 要在 resultMap 里面进行的。

    <mapper namespace="com.muquanyu.Mapper.StudentMapper">
        <select id="getStudentList" resultMap="StudentTeacher">
            select * from mybatis.student
        </select>
        <resultMap id="StudentTeacher" type="com.muquanyu.pojo.Student">
            <result property="id" column="id"></result>
            <result property="name" column="name"></result>
            <association property="teacher" column="tid" javaType="com.muquanyu.pojo.Teacher" select="getTeacher"></association>
        </resultMap>
    
        <select id="getTeacher" resultType="com.muquanyu.pojo.Teacher">
            select * from mybatis.teacher where id = #{tid}
        </select>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    getTeacher 这个方法 它是 不在 我们的 StudentMapper 接口里面 声明的。那 它 怎么能应用呢?又如何能够 有效呢?答案是:利用 resultMap 的 association 子标签 select 属性 绑定 getTeacher 实现 子查询!!!

    association 子标签的使用是 先让你 做简单的绑定,就是 属性名是什么,对应的 字段名是什么,然后 要 对 javaType 和 select 进行绑定,javaType 是绑定 你通过 该字段 要去 查一个 什么表,转到java里的意思,就是 你要去查一个 什么对象,然后提供这个 类型就行。那么通过 哪个方法 去查,这个时候 用 select 去绑定 你写在 xml 里面的 sql 方法就行了。

    但实际上,我们 无论是 使用 SQL 还是 使用 mybatis 都会发现 这种 子查询的 方式 很麻烦。所以 我们 要 介绍 第二个 方式 “resultMap 结果关联”

    1. resultMap 结果关联

    它之所以方便,是因为 我们的 SQL 语句 该是什么样子,就是什么样就行。然后 直接 通过 resultMap 去调节就可以了

    <?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.muquanyu.Mapper.StudentMapper">
        <resultMap id="StudentMapB" type="top.muquanyu.pojo.Student">
            <id property="id" column="sid"></id>
            <result property="name" column="sname"></result>
            <association property="teacher" javaType="top.muquanyu.pojo.Teacher">
                <id property="id" column="tID"></id>
                <result property="name" column="tname"></result>
            </association>
        </resultMap>
    
        <select id="getListB" resultMap="StudentMapB">
            select s.id sid,s.name sname,s.tid,t.id tID,t.name tname from
            test.teacher t join test.student s on t.id = s.tid
        </select>
    </mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述
    在这里插入图片描述


    8.2.1 collection 一对多

    比如:一个老师 拥有 多个 学生,这就是 一对多。

    • 联表查询
    <?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.muquanyu.Mapper.TeacherMapper">
    
       <resultMap id="TeacherMap" type="top.muquanyu.pojo.Teacher">
           <id property="id" column="Tid" ></id>
           <result property="name" column="tname" ></result>
           <collection property="students" ofType="top.muquanyu.pojo.Student">
               <id property="id" column="sid"></id>
               <result property="name" column="sname"></result>
               <result property="tid" column="tid"></result>
           </collection>
       </resultMap>
    
    
       <select id="getListByID" resultMap="TeacherMap">
           select s.id sid,s.name sname,s.tid tid,t.id Tid,t.name tname from
           test.teacher t join test.student s on s.tid = t.id and t.id = #{id}
       </select>
    </mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    xml 配置里面的 ofType 代表的是 泛型类型,就是说 你这个集合 泛型是什么类型的。你需要配置一下。

    为什么 链表查询的 collection 里面 没有 对应的 javaType 呢?

    答:因为不需要!我们联表查询,已经明确的指出 我们要查询的就是一个集合,序列。所以不需要 告诉 collection javaType = ArrayList 了!

    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    import top.muquanyu.Mapper.TeacherMapper;
    import top.muquanyu.pojo.Teacher;
    import top.muquanyu.utils.MybatisUtils;
    
    public class 一对多 {
        @Test
        public void test(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
            for (Teacher teacher : mapper.getListByID(1)) {
                System.out.println(teacher);
            }
            sqlSession.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 子查询
    
    <?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.muquanyu.Mapper.TeacherMapper">
        <resultMap id="TeacherMapB" type="top.muquanyu.pojo.Teacher">
            <id property="id" column="id"></id>
            <result property="name" column="name"></result>
            <collection property="students" column="id" javaType="ArrayList" ofType="student" select="getStudent"></collection>
        </resultMap>
    
        <select id="getListByIDB" resultMap="TeacherMapB">
            select * from test.teacher where id = #{id}
        </select>
    
        <select id = "getStudent" resultType="top.muquanyu.pojo.Student">
            select * from test.student where tid = #{tid}
        </select>
    
    </mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    子查询 的 多对一和一对多,column 指的是 哪个字段 可以 跟 你要 关联的表 进行 关联的。比如说 多对一时 的 学生 tid 就是跟 老师表 关联的,所以 要写 column = tid,而 一对多 的 老师的 id 跟 查询学生 时 的 关键条件 where tid = #{tid} 有明显 关联,这个 tid 其实 指的就是 老师 的 id。所以 column = id。 然后 它在 进行 返回的时候,是直接 传参的,也就是说 不用 特别在意 select 绑定的方法 sql 语句 #{参数名} 与 这个 column 绑定的字段名 不一致。因为 是直接 返回 传参的。所以 不需要 名字一致!

    javaType 绑定 实体类中的 主 java 类型一对多,链表查询的时候可以不用写!
    ofType 绑定 集合中 的 泛型类型


    8.2.2 注意点

    • 保证 SQL 的可读性,尽量保证 通俗易懂
    • 注意 一对多 和 多对一 当中的 属性名 和 字段 对应问题。
    • 如果 问题 不好排查 错误,可以 使用 日志。这里建议 用 log4j

    SQL 面试高频问题:

    • MySQL 引擎
    • InnoDB 底层原理
    • 索引的使用
    • 索引优化
  • 相关阅读:
    LabVIEW中使用并口
    五城联动!尧泰汉海“四季有爱·益路向阳”公益活动圆满落幕
    ReentrantLock 类 源代码详细解释
    数据结构与算法编程题2
    Swagger
    从React源码分析看useEffect
    【C++】list的使用(上)
    《上海市交通领域科技创新发展行动计划》发布
    蓝牙协议栈分层
    AD9371 官方例程HDL详解之JESD204B RX侧时钟生成
  • 原文地址:https://blog.csdn.net/qq_52606908/article/details/124581229