Mybatis多表关联查询之多对多
周sir |
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多表关联查询之多对多
我是周sir,这是我的博客。致力于分享我学会的技术和优秀的文章。微信公众号 “周sir专栏” 欢迎大家关注。