10.关联关系查询
Posted 白日梦想家12138
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了10.关联关系查询相关的知识,希望对你有一定的参考价值。
关联关系查询
当查询内容涉及到具有关联关系的多个表时,就需要使用关联查询
根据表与表间的关联关系的不同,关联查询分为四种:
(1)一对一关联查询
(2)一对多关联查询
(3)多对一关联查询
(4)多对多关联查询
由于日常工作中最常见的关联关系是一对多、多对一与多对多,所以这里就不专门只讲
解一对一关联查询了,其解决方案与多对一解决方案是相同的。
1.一对多关联查询
在查询一方的时候,同时将其所关联的多方对象也都查询出来
A、多表连接查询方式(一条SQL语句):
1 <mapper namespace="com.mybatis.dao.CountryDAO" > 2 <!-- parameterType 可以省略 --> 3 4 <resultMap type="Country" id="countryMapper"> 5 <!-- 和解决字段名和属性名不相同的问题 不同,在这里,就算属性名和数据库中的字段名一致,也要写出来,不会主动帮你填入的 --> 6 <id column="cid" property="cid"/> 7 <result column="cname" property="cname"/> 8 <!-- 一对多,一的一方存储了多的一方,以集合的形式,collection标签可以帮助我们完成 集合里面对象的构成 --> 9 <collection property="ministers" ofType="Minister"> 10 <id column="mid" property="mid"/> 11 <result column="mname" property="mname" /> 12 </collection> 13 </resultMap> 14 15 16 <!-- 多表连接查询方式,这种方式 无法进行延迟加载,多的一方直接跟着 一的一方一起查出来了,会消耗很多资源 --> 17 <select id="selectCountryById" resultMap="countryMapper"> 18 <!-- 查询出了这四个字段,但是这四个字段是无法直接构成country对象的 ,故使用resultMap,让其将mid,mname构成ministers,再构成country--> 19 select cid,cname,mid,mname from country,minister where countryId = cid and cid = #{cid} 20 </select> 22 </mapper>
在映射文件中使用 <collection/>标签体现出两个实体对象间的关联关系。其两个属性的意义位:
property:指定关联类型,即Country类中的集合类型
ofType:集合属性的泛型类型
B、多表单独查询方式(多条SQL语句)
多表连接查询方式是将多张表进行连接,连为一张表后进行查询。其查询的本质是一张表。
而多表单独查询方式是多张表各自查询各自的相关内容,需要多张表的联合数据了,
则 将主表的查询结果联合其它表的查询结果,封装为一个对象。
当然,这多个查询是可以跨越多个映射文件的,即是可以跨越多个 namespace 的。
在 使用其它 namespace 的查询时,添加上其所在的 namespace 即可
1 <mapper namespace="com.mybatis.dao.CountryDAO" > 2 3 <resultMap type="Country" id="countryMapper"> 4 <id column="cid" property="cid"/> 5 <result column="cname" property="cname"/> 6 <!-- 执行到这里时,会调用 select 属性中的 SQL,column 作为外键参数,cid--> 7 <collection property="ministers" ofType="Minister" select="selectMinisterByCountry" column="cid"> 8 </collection> 9 </resultMap> 10 11 <!-- 使用多表单独查询的方式(使用多条SQL语句) 采用这种方式,可以实现延迟加载--> 12 <!-- 由DAO调用,故先执行 selectCountryById ,执行到collection,这时需要 执行 selectMinisterByCountry --> 13 <select id="selectCountryById" resultMap="countryMapper"> 14 select cid,cname from country where cid = #{cid} 15 </select> 16 <select id="selectMinisterByCountry" resultType="Minister"> 17 select mid,mname from minister where countryId = #{countryId} 18 </select> 19 20 </mapper>
关联属性<collection/>的数据来自于另一个查询<selectMinisterByCountry/>。
而该查询<selectMinisterByCountry/>的动态参数 countryId=#{ooo}的值来自于查询<selectCountryById/>的查询结果字段 cid
2.多对一关联查询
在查询多方对象的时候,同时将其所关联的一方对象也查 询出来。
由于在查询多方对象时也是一个一个查询,所以多对一关联查询,其实就是一对一关联查询
即一对一关联查询的实现方式与多对一的实现方式是相同的
1 <mapper namespace="com.mybatis.dao.MinisterDAO" > 2 <!-- parameterType 可以省略 --> 3 4 <resultMap type="Minister" id="ministerMapper"> 5 <!-- 和解决字段名和属性名不相同的问题 不同,在这里,就算属性名和数据库中的字段名一致,也要写出来,不会主动帮你填入的 --> 6 <id column="mid" property="mid"/> 7 <result column="mname" property="mname"/> 8 9 <!-- 多对一采用的是 association 来完成关联属性的构成 --> 10 <association property="country" javaType="Country"> 11 <id column="cid" property="cid"/> 12 <result column="cname" property="cname"/> 13 </association> 14 </resultMap> 15 16 17 <!-- 多表连接查询方式,这种方式 无法进行延迟加载,多的一方直接跟着 一的一方一起查出来了,会消耗很多资源 --> 18 <select id="selectMinisterById" resultMap="ministerMapper"> 19 select mid,mname,cid,cname from minister,country where mid = #{mid} and countryId = cid 20 </select> 21 22 </mapper>
注意:在映射文件中使用 <association/> 标签体现出两个实体对象间的关联关系
property:指定关联属性,即Minister类中的 country属性
javaType:关联属性的类型
多表单独查询的方式
1 <mapper namespace="com.mybatis.dao.MinisterDAO" > 2 <!-- parameterType 可以省略 --> 3 4 <resultMap type="Minister" id="ministerMapper"> 5 <!-- 和解决字段名和属性名不相同的问题 不同,在这里,就算属性名和数据库中的字段名一致,也要写出来,不会主动帮你填入的 --> 6 <id column="mid" property="mid"/> 7 <result column="mname" property="mname"/> 8 9 <!-- 多对一采用的是 association 来完成关联属性的构成 --> 10 <association property="country" javaType="Country" select="selectCountryById" column="countryId"> 11 <id column="cid" property="cid"/> 12 <result column="cname" property="cname"/> 13 </association> 14 </resultMap> 15 16 17 <!-- 使用多表单独查询的方式(使用多条SQL语句) 采用这种方式,可以实现延迟加载--> 18 <select id="selectMinisterById" resultMap="ministerMapper"> 19 select mid,mname,countryId from minister where mid = #{mid} 20 </select> 21 22 <select id="selectCountryById" resultType="Country"> 23 select cid,cname from country where cid = #{countryId} 24 </select> 25 26 </mapper>
3.自关联查询
所谓自关联是指,自己即充当一方,又充当多方,是 1:n 或 n:1 的变型
例如,对于新闻栏目 NewsColumn,可以充当一方,即父栏目,也可以充当多方,即子栏目。而反映到 DB 表中,只有一张表,这张表中具有一个外键,用于表示该栏目的父栏目。一级栏目没有父栏 目,所以可以将其外键值设为 0,而子栏目则具有外键值。
为了便于理解,将自关联分为两种情况来讲解。一种是当作 1:n 讲解,即当前类作为一 方,其包含多方的集合域属性。一种是当作 n:1 讲解,即当前类作为多方,其包含一方的域 属性。
下面以新闻栏目为例进行讲解。由于 Column 是 DBMS 中的关键字,为了避免误解,将 新闻栏目实体类定义为 NewsLabel。
以一对多方式处理:
以一对多方式处理,即一方可以看到多方。该处理方式的引用场景比较多,例如在页面上点击父栏目,显示出其子栏目
A、查询指定栏目的所有子孙栏目:
1 <mapper namespace="com.mybatis.dao.NewsLabelDAO" > 2 3 <!-- 自关联查询 --> 4 5 <resultMap type="NewsLabel" id="newsLabelMapper"> 6 <id property="id" column="id"/> 7 <result property="name" column="name"/> 8 <!-- pid动态参数值 来自上一次查询的结果的 id 值 --> 9 <collection property="chirldren" ofType="NewsLabel" select="selectChildrenByParentId" column="id"/> 10 11 </resultMap> 12 13 <!-- select 语句的递归调用 --> 14 <!-- 过程:1.先查到 3,4是2 的 子元素 15 2.深度优先,从3开始下手,在构造3的chirldren属性时,需要去查3下面是否有子元素(因为collection中 使用的select 语句是selectChildrenByParentId) 16 这就构成了递归,如果3下面有子元素,则再递归着去查这个子元素下面是否还要子元素 17 18 --> 19 <select id="selectChildrenByParentId" resultMap="newsLabelMapper"> 20 select id,name from newslabel where pid = #{pid} 21 </select> 22 23 24 </mapper>
B、查询指定栏目及其所有子孙栏目:
这里的查询结果,即要包含指定 id 的当前栏目,还包含其所有辈份的孙子栏目。
即给 出的 id 实际为当前要查询的栏目的 id。
1 <!-- 自关联查询 --> 2 <resultMap type="NewsLabel" id="newsLabelMapper"> 3 <id property="id" column="id"/> 4 <result property="name" column="name"/> 5 <!-- pid动态参数值 来自上一次查询的结果的 id 值 --> 6 <collection property="chirldren" ofType="NewsLabel" select="selectChildrenByParent" column="id"/> 7 8 </resultMap> 9 10 <!-- 1.先根据查出 查出对应的 NewsLabel --> 11 <select id="selectNewsLabelById" resultMap="newsLabelMapper"> 12 select id,name from newslabel where id = #{id} 13 </select> 14 15 <!-- 2.再根据前一次出的id 作为 pid,查询这个id 下所有的子元素 --> 16 <select id="selectChildrenByParent" resultMap="newsLabelMapper"> 17 select id,name from newslabel where pid = #{id} 18 </select> 19 20 21 22 23 </mapper>
以多对一方式处理:
以多对一方式处理,即多方可以看到一方
1 <!-- 自关联查询 --> 2 3 <resultMap type="NewsLabel" id="newsLabelMapper"> 4 <id property="id" column="id"/> 5 <result property="name" column="name"/> 6 <!-- pid动态参数值 来自上一次查询的结果的 id 值 --> 7 <association property="parent" javaType="NewsLabel" select="selectParentByParentId" column="pid"/> 8 9 </resultMap> 10 11 <select id="selectParentByParentId" resultMap="newsLabelMapper"> 12 select id,name,pid from newslabel where id = #{pid} 13 </select> 14 15 16 </mapper>
4.多对多关联查询
什么是多对多关联关系?一个学生可以选多门课程,而一门课程可以由多个学生选。这就是典型的多对多关系关系。
所以,所谓多对多关系,其实是由两个互反的一对多关系组成。
一般情况下,多对多关系都会通过一个中间表来建立,例如选课表。
多对多关联关系也是通过映射文件<resultMap/>的<cooection/>体现的
但是,需要注意的是SQL语句中是对三张表的连接查询
1 <!-- 多对多查询 --> 2 3 <resultMap type="Student" id="studentMapper"> 4 <id property="sid" column="sid"/> 5 <result property="sname" column="sname"/> 6 <collection property="courses" ofType="Course" > 7 <id property="cid" column="cid"/> 8 <result property="cname" column="cname"/> 9 </collection> 10 11 </resultMap> 12 13 <select id="selectStudentById" resultMap="studentMapper"> 14 select sid,sname,cid,cname from student,course,middle where sid = studentId and cid = courseId and sid = #{sid} 15 </select>
以上是关于10.关联关系查询的主要内容,如果未能解决你的问题,请参考以下文章