Mybatis多表关联查询之多对多

    |     2017年6月15日   |   mytatis   |     0 条评论   |    3902

MyBatis 多表关联分成四种:一对一、一对多、多对一、多对多。映射关键仍是 resultMap,可参考 MyBatis学习 之 二、SQL语句映射文件(1)resultMap。本文只做多对多:学生和课程彼此没有外键,中间表 t_stu_cou 用 in 查出另一侧 id 列表。

属性类型是集合用 collection,是单个对象用 association。默认 TypeAliasRegistry 已挂上 JDK 常用类,所以 javaType="java.lang.Integer" 也可写成 javaType="Integer"。

一、表结构与类结构

表结构

类结构

查询 resultMap 是否带另一侧
findCouById coursesMap 只查课程
findCouAndStu couAndStu 课程 + 选修学生
findStuById studentMap 只查学生
findStuAndCou studentAndCourses 学生 + 选修课程

二、CoursesMapper.xml

按课程 id 查学生时,学生 id 不是单值,要用中间表 fk_cou_id 取出 fk_stu_id,SQL 里写 in。

<mapper namespace="com.ittx.mybatis.demo1.dao.CoursesDao">
    <resultMap type="com.ittx.mybatis.demo1.model.Courses"
        id="coursesMap">
        <!-- 默认 TypeAliasRegistry 会挂上很多 JDK 常用类,javaType="java.lang.Integer" 可以写成 javaType="Integer" -->
        <id property="id" column="cid" javaType="java.lang.Integer" />
        <result property="name" column="courses_name" javaType="java.lang.String" />
    </resultMap>

    <resultMap type="com.ittx.mybatis.demo1.model.Courses"
        id="couAndStu">
        <id property="id" column="cid" javaType="java.lang.Integer" />
        <result property="name" column="courses_name" javaType="java.lang.String" />

        <!-- 属性是集合用 collection,属性是类用 association -->
        <collection property="student" column="cid"
            select="findStudentByCourses"></collection>
    </resultMap>

    <!-- 学生表、课程表都没有外键,用第三张关联表;根据 fk_cou_id 得到学生 id,多对多时 id 不是单值,数据库里用 in -->
    <select id="findStudentByCourses" resultMap="com.ittx.mybatis.demo1.dao.StudentDao.studentMap">
        select * from
        t_student where sid in (select fk_stu_id from t_stu_cou where
        fk_cou_id=#{id})
    </select>
    <!-- resultMap="coursesMap" 只根据课程 id 找课程,不关联选修学生 -->
    <select id="findCouById" resultMap="coursesMap">
        select * from t_courses where
        cid=#{id}
    </select>
    <!-- resultMap="couAndStu" 根据课程 id 找课程,同时关联查询选修该课的学生 -->
    <select id="findCouAndStu" resultMap="couAndStu">
        select * from t_courses
        where cid=#{id}
    </select>
</mapper>

三、StudentMapper.xml

从学生出发查课程,对称地按 fk_stu_id 去中间表取 fk_cou_id。

<mapper namespace="com.ittx.mybatis.demo1.dao.StudentDao">

    <resultMap type="com.ittx.mybatis.demo1.model.Student"
        id="studentMap">
        <id property="id" column="sid" javaType="java.lang.Integer" />
        <result property="name" column="student_name" javaType="java.lang.String" />
    </resultMap>

    <resultMap type="com.ittx.mybatis.demo1.model.Student"
        id="studentAndCourses">
        <id property="id" column="sid" javaType="java.lang.Integer" />
        <result property="name" column="student_name" javaType="java.lang.String" />
        <collection property="courses" column="sid"
            select="findCoursesByStudent"></collection>
    </resultMap>

    <select id="findCoursesByStudent" resultMap="com.ittx.mybatis.demo1.dao.CoursesDao.coursesMap">
        select * from t_courses where cid in (select fk_cou_id from t_stu_cou where
        fk_stu_id = #{id})
    </select>
    <!-- resultMap="studentMap" 只根据学生 id 找学生,不关联选修课程 -->
    <select id="findStuById" resultMap="studentMap">
        select * from t_student where sid = #{id}
    </select>
    <!-- resultMap="studentAndCourses" 根据学生 id 找学生,同时关联查询选修课程 -->
    <select id="findStuAndCou" resultMap="studentAndCourses">
        select * from t_student where sid = #{id}
    </select>
</mapper>

一句话总结:多对多没有直接外键,用中间表 + collection 的嵌套 select;同一套 Mapper 提供「只查自己」和「带出对侧集合」两套 resultMap,避免每次都 N+1。

转载请注明来源:Mybatis多表关联查询之多对多
本文链接地址:https://ai.zhousir.top/?p=1992
回复 取消