1.关联查询
当查询内容涉及到具有关联关系的多个表时,就需要使用关联查询。根据表与表间的关联关系的不同,关联查询分为四种:
(1)一对一关联查询
(2)一对多关联查询
(3)多对一关联查询
(4)自关联
(5)多对多关联查询
由于日常工作中最常见的关联关系是一对多、多对一与多对多,所以这里就不专门只讲解一对一关联查询了,其解决方案与多对一解决方案是相同的。
-
一对多关联查询
这里的一对多关联查询是指,在查询一方对象的时候,同时将其所关联的多方对象也都查询出来
下面是国家Country 与 部长Minister间的一对多关系进行演示.
-
- 建表
country表
minister表
- 实体
- 一对多通过多表连接查询实现
<mapper namespace="com.ryanxu.dao.ICountryDao"> <resultMap type="Country" id="countryMapper"> <id column="cid" property="cid" /> <result column="cname" property="cname" /> <collection property="ministers" ofType="Minister"> <id column="mid" property="mid" /> <result column="mname" property="mname" /> </collection> </resultMap> <select id="selectCountryById" resultMap="countryMapper"> select cid,cname,mid,mname from country join minister on country.cid = minister.countryId where cid = #{id} </select> </mapper>
注意 result里面 column和property之间要有空格 不然会报错
Cause: org.xml.sax.SAXParseException: Element type "result" must be followed by either attribute specifications, ">" or "/>".
因为是多表查询 返回的有minister的成员变量 若resultType使用的是Country 则没有mid和mname的get/set方法 所以使用resultMapper 将返回的包装成Country类 collection就是Set里面就是minister
- 测试
-
- 一对多通过多表单独查询实现
<select id="selectMinisterByCountry" resultType="Minister"> select mid,mname from minister where countryId = #{ryanxu} </select> <resultMap type="Country" id="countryMapper"> <id column="cid" property="cid"/> <result column="cname" property="cname"/> <collection property="ministers" ofType="Minister" select="selectMinisterByCountry" column="cid"/> </resultMap> <select id="selectCountryById" resultMap="countryMapper"> select cid,cname from country where cid = #{cid} </select>
-
- 测试
- 多对一关联查询
-
- 实体
-
-
- 多对一通过多表连接查询实现
<?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="com.ryanxu.dao.IMinisterDao"> <resultMap type="Minister" id="MinisterMapper"> <id column="mid" property="mid" /> <result column="mname" property="mname" /> <association property="country" javaType="Country"> <id column="cid" property="cid" /> <result column="cname" property="cname" /> </association> </resultMap> <select id="selectMinisterById" resultMap="MinisterMapper"> select mid,mname,cid,cname from minister join country on minister.countryId = cid where mid = #{mid} </select> </mapper>
- 测试
- 多对一通过多表单独查询方式实现
<select id="selectCountryById" resultType="Country"> select cid,cname from country where cid = #{cid} </select> <resultMap type="Minister" id="MinisterMapper"> <id column="mid" property="mid"/> <result column="mname" property="mname"/> <association property="country" javaType="Country" select="selectCountryById" column="countryId"/> </resultMap> <select id="selectMinisterById" resultMap="MinisterMapper"> select mid,mname,countryId from minister where mid = #{mid} </select>
- 测试
- 自关联查询
(1)自关联的DB表
(2)以一对多方式处理
(A)查询指定栏目的所有子孙栏目
<?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="com.ryanxu.dao.INewsLableDao"> <!-- <select id="selectChildrenByParent" resultMap="newslabelMapper"> select id,name from newslabel where pid = #{pid} </select> --> <resultMap id ="newslabelMapper" type="NewsLabel"> <id column="id" property="id"/> <result column="name" property="name"/> <collection property="children" ofType="NewsLabel" select="selectChildrenByParent" column="id"/> </resultMap> <select id="selectChildrenByParent" resultMap="newslabelMapper"> select id,name from newslabel where pid = #{pid} </select> </mapper>
(B)查询指定栏目及其所有子孙栏目
<select id="selectChildrenByParent" resultMap="newslabelMapper"> select id,name from newslabel where pid=#{pid} </select> <resultMap id ="newslabelMapper" type="NewsLabel"> <id column="id" property="id"/> <result column="name" property="name"/> <collection property="children" ofType="NewsLabel" select="selectChildrenByParent" column="id"/> </resultMap> <select id="selectNewsLabelById" resultMap="newslabelMapper"> select id,name from newslabel where id = #{id} </select>
(3)以多对一方式处理(查询当前栏目和所有的父栏目)
<resultMap id ="newslabelMapper" type="NewsLabel"> <id column="id" property="id"/> <result column="name" property="name"/> <association property="parent" javaType="NewsLabel" select="selectNewsLabelById" column="pid"/> </resultMap> <select id="selectNewsLabelById" resultMap="newslabelMapper"> select id,name,pid from newslabel where id = #{id} </select>
- 多对多关联查询
- 实体类
<?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="com.ryanxu.dao.IStudentDao"> <resultMap id="studentMapper" type="Student"> <id column="sid" property="sid" /> <result column="sname" property="sname" /> <collection property="cources" ofType="Course"> <id column="cid" property="cid" /> <result column="cname" property="cname" /> </collection> </resultMap> <select id="selectStudentById" resultMap="studentMapper"> select sid,sname,cid,cname from student join sc on student.sid = sc.studentId join course on sc.courseId = course.cid where sid = #{sid} </select> </mapper>
2.关联查询
- 概念:Mybatis中的延迟加载,也称为懒加载,是指在进行关联查询时,按照设置延迟规则推迟对关联对象的select查询。延迟加载可以有效地减少数据库压力。需要注意的是,Mybatis的延迟加载只是对关联对象的查询有延迟设置,对于主加载对象都是直接执行查询语句的。
- 加载时机
直接加载:执行完对主加载对象的select语句,马上执行对关联对象的select查询。
侵入式延迟:执行对主加载对象的查询时,不会执行对关联的查询。但当要访问主加载对象的详情时,就会马上执行关联对象的select查询。即对关联对象的查询执行,侵入到了主加载对象的详情访问中。也可以这样理解:将关联对象的详情侵入到了主加载对象 的详情中,即将关联对象的详情作为主加载对象的详情的一部分出现了。
深度延迟:执行对主加载对象的查询时,不会执行对关联对象的查询。访问主加载对象的详情时也不会执行关联对象的select查询。只有当真正访问关联对象的详情时,才会执行对关联对象的select查询。
需要注意的是,延迟加载的应用要求,关联对象的查询与主加载对象的查询必须是分别进行的select语句,不能是使用多表连接所进行的select查询。因为,多表连接查询,其实质是对一张表的查询,对由多个表连接后形成的一张表的查询。会一次性将多张表的 所有信息查询出来。
- 加载配置
延迟加载配置放在settings标签下 settings在properties之后
延迟加载的总开关是 lazyLoadingEnabled 默认是false 这种情况下就是直接加载
侵入式加载的开关是 aggressiveLazyLoading 默认是true 所以只要将总开关打开 就是侵入式加载了
将侵入式加载的开关关掉 false 那么就是深度延迟了
<!-- 设置整个应用所使用的常量 --> <settings> <!-- 延迟加载的总开关 --> <setting name="lazyLoadingEnabled" value="true"/> <!-- 侵入式延迟加载开关 --> <setting name="aggressiveLazyLoading" value="false"/> </settings>