互联网轻量级框架SSM-查缺补漏第六天【级联+延迟加载特辑】
简言:本来这是昨天看的,但是因为想好好写一下【级联】这个东西,所以就看完之后今天来整理一下。
级联
1. 什么是级联
级联是一个数据库实体的概念。比如教师就需要存在学生与之对应,这样就有教师学生表,一个教师可能有多个学生,这就是一对多的级联;除此之外还有一对一的级联,比如身份证和公民是一对一的关系;再例如用户与角色的关系,一个用户有多个角色,一个角色也可能有多个用户,这就是多对多的级联。(在MyBatis中多对多的级联可以用两个一对多的级联进行代替)
级联不是必须的,级联的好处是获取关联数据十分便捷,但是级联过多会增加系统的复杂度,同时降低系统的性能,此增彼减,所以当级联的成绩超过3层时,就不要考虑使用级联了,因为这样会造成对个对象的关联,导致系统的耦合、复杂和难以维护。在现实的使用过程中,要根据实际情况判断是否需要使用级联。
2. MyBatis中的级联
MyBatis的级联分三种:
- 鉴别器(discriminator):它是一个根据某些条件决定采用具体哪类级联的方案(说白了就是根据给出的条件去判断采用哪种级联,有点JavaSE中Switch的感觉,而且鉴别器也可以不去采用级联,而是直接映射关系,下面会有介绍)
- 一对一(association):比如学生证和学生就是一种一对一的级联
- 一对多(collection):比如老师和学生就是一种一对多的级联
3. 级联的配置与使用
一对一的级联:
拿身份证和公民的关系举例:先建两个POJO文件。假设要得到公民信息。
/* 公民类 */
public class person {
private int id;
private String name;
private IDCard idCard;
/* getters and setters */
}
/* 身份证类 */
public class IDCard {
private long id;
private String name;
private String addr;
/* getters and setters */
}
在公民中有一个身份证类型的属性用来存身份证信息,而在数据库中表的创建只需要存一个身份证的ID,这里我就不贴上表的创建了。接下来配置好Mapper配置文件。我这里写XML的配置方法。
<resultMap type="person" id="PersonMap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<association property="idCard" column="card_id" select="com.learn.ssm.chapter5.mapper.PersonMap.getIDCard"></association>
</resultMap> <select id="getIDCard" resultType="idcard">
select * from t_idcard
</select> <select id="getPersonInfo" resultMap="PersonMap">
select * from t_person
</select>
首先配置一个resultMap元素,type的值person是公民类的别名。第4行中,property表示association的值保存到公民类的身份证属性中,card_id表示数据库中的身份证号字段,关键的是select属性,将会调用其值所对应的方法(也就是下面的getIDCard方法),并得到返回值存到idCard属性中。
如果对resultMap的简单使用不熟悉的请参考我之前的随笔~
一对多的级联:
举例:老师和学生的关系,老师对应着很多学生,假设要得到老师信息。也先建立两个POJO文件。
public class Teacher {
private int id;
private String name;
private List<Student> studentList;
/* getters and setters */
}
public class Student {
private long id;
private String name;
private String sex;
private String teacherName;
/* getters and setters */
}
老师的POJO中用一个list集合来存储学生信息。在学生信息中有teacherName属性用来对应相应的老师。
<resultMap type="teacher" id="TeacherMap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<collection property="studentList" column="name" select="com.learn.ssm.chapter5.mapper.PersonMap.getStudentInfoByTeacherName"></collection>
</resultMap> <select id="getStudentInfoByTeacherName" parameterType="String" resultMap="student">
select * from t_student where teacher_name = #{teacherName}
</select> <select id="getTeacherInfo" resultMap="TeacherMap">
select * from t_teacher
</select>
与一对一的级联关系相似,只是用教师名字查询的结果会是多条,将会存到studentList属性中。
鉴别器:
举例:假设在一对多例子中,数据库中教师表有一个stu_sex的字段,用来过滤学生的性别的。可能我这个例子不是很实际,但是也不难理解。如果stu_sex字段是0的·话,查询的时候就只查出男学生,反之是1的话就自查出女学生。假设要查教师信息了。
<resultMap type="teacher" id="TeacherMap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<discriminator javaType="long" column="stu_sex">
<case value="0" resultMap="maleStuMap"></case>
<case value="1" resultMap="femaleStuMap"></case>
</discriminator>
</resultMap> <resultMap type="student" id="maleStuMap" extends="TeacherMap">
<collection property="studentList" column="name" select="com.learn.ssm.chapter5.mapper.PersonMap.getMaleStuInfoByTeacherName"></collection>
</resultMap> <resultMap type="student" id="femaleStuMap" extends="TeacherMap">
<collection property="studentList" column="name" select="com.learn.ssm.chapter5.mapper.PersonMap.getFemaleStuInfoByTeacherName"></collection>
</resultMap> <select id="getMaleStuInfoByTeacherName" parameterType="String" resultMap="student">
select * from t_student where teacher_name = #{teacherName} and sex = '男'
</select> <select id="getFemaleStuInfoByTeacherName" parameterType="String" resultMap="student">
select * from t_student where teacher_name = #{teacherName} and sex = '女'
</select> <select id="getTeacherInfo" resultMap="TeacherMap">
select * from t_teacher
</select>
就像前面解释的,鉴别器就相当于switch,它不去直接产生级联关系,它调用其他resultMap中的级联关系。从而做到选择功能。
extends很重要的。我刚开始以为extends在resultMap中起到继承作用(就是如果两个结果集有继承关系的话,子类结果集继承父类的映射),后来看到这里的时候,查了下api文档。如果在使用鉴别器的时候,被调用的resultMap没有extends属性的话,将之返回子resultMap的结果。在本例子中也就是只返回男学生们或者女学生们。
api中的意思:如果没有extends的话,就会被当成独立组,和父类没有什么关系。贴上API连接~~~~【点击这里】
鉴别器也可以直接去映射关系,举例:
<resultMap id="vehicleResult" type="Vehicle">
<id property="id" column="id" />
<result property="vin" column="vin"/>
<result property="year" column="year"/>
<result property="make" column="make"/>
<result property="model" column="model"/>
<result property="color" column="color"/>
<discriminator javaType="int" column="vehicle_type">
<case value="1" resultMap="carResult"/>
<case value="2" resultMap="truckResult"/>
<case value="3" resultMap="vanResult"/>
<case value="4" resultMap="suvResult"/>
</discriminator>
</resultMap>
<resultMap id="carResult" type="Car" extends="vehicleResult">
<result property="doorCount" column="door_count" />
</resultMap>
如果嫌这么麻烦的话,还有种写法:
<resultMap id="vehicleResult" type="Vehicle">
<id property="id" column="id" />
<result property="vin" column="vin"/>
<result property="year" column="year"/>
<result property="make" column="make"/>
<result property="model" column="model"/>
<result property="color" column="color"/>
<discriminator javaType="int" column="vehicle_type">
<case value="1" resultType="carResult">
<result property="doorCount" column="door_count" />
</case>
<case value="2" resultType="truckResult">
<result property="boxSize" column="box_size" />
<result property="extendedCab" column="extended_cab" />
</case>
<case value="3" resultType="vanResult">
<result property="powerSlidingDoor" column="power_sliding_door" />
</case>
<case value="4" resultType="suvResult">
<result property="allWheelDrive" column="all_wheel_drive" />
</case>
</discriminator>
</resultMap>
多对多关系:
之前介绍了多对多的关系就是两个一对多,举例:角色与用户的关系,角色有多个用户,用户也包含多个角色。这里就需要三张表,用户表,角色表,和用户角色关系表。
贴上POJO
public class User2 {
private int id;
private String name;
//角色列表
private List<Role2> roleList;
/* getters and setters */
} public class Role2 {
private long id;
private String userName;
private String note;
//用户列表
private List<User2> userList;
/* getters and setters */
}
若要取用户信息的话:
<resultMap type="user2" id="UserMap">
<id column="id" property="id"/>
<result column="user_name" property="userName"/>
<collection property="roleList" column="id" select="com.learn.ssm.chapter5.mapper.UserMapper.getRoleInfoByUserId"></collection>
</resultMap> <select id="getRoleInfoByUserId" parameterType="long" resultMap="role2">
select r.* from t_user_role ur join t_role r on r.id = ur.role_id where ur.role_id = #{id}
</select> <select id="getUser" resultMap="UserMap">
select * from t_user
</select>
若要获取角色信息:
<resultMap type="role2" id="RoleMap">
<id column="id" property="id"/>
<result column="role_name" property="roleName"/>
<collection property="userList" column="id" select="com.learn.ssm.chapter5.mapper.UserMapper.getUserInfoByRoleId"></collection>
</resultMap> <select id="getUserInfoByRoleId" parameterType="long" resultMap="user2">
select u.* from t_user_role ur join t_user u on u.id = ur.user_id where ur.user_id = #{id}
</select> <select id="getRole" resultMap="RoleMap">
select * from t_role
</select>
4 N+1问题
比如在一个雇员信息中,它的任务信息、体检表和工牌信息都是通过级联来取的。此时我只想加载它的基本信息和任务信息,那么体检表和工牌信息就不需要去取,因为这些信息不需要使用,加载他们会多执行几条毫无用处的SQL,会导致数据库资源的损耗和性能的下降。
关系如下:(这是我《JAVAEE 互联网轻量级框架整合开发(SSM)》书上的例子,就简单来看看,虽然我形容的比较简单,但是还是能懂的)
N+1的由来:假设有N个关联关系完成了级联,那么只要加入一个关联关系,就变成了N+1个级联,所有的级联SQL都会被执行,显然会有很多并不是我们关心的数据被取出,这样会造成很大的资源浪费。尤其是在那些需要高性能的互联网系统中,这往往是不被允许的。
为了应对N+1问题,MyBatis提供了延迟加载功能
在MyBatis的settiings配置中有两个元素控制延迟加载功能:
- lazyLoadingEnabled:顾名思义,延迟加载开关,默认为false,不开启。值为true时开启。
- aggressiveLazyLoading:3.4.2版本之后默认值为false,之前一致为true。这个元素的意思就是有“有进取心的延迟加载”,值为true,表示它有进取心,所以不管你要不要那些没用的级联信息,都给你加载出来(N+1个信息都给你加载出来)。值为false时,就把你所需要的,想看见的给你加载出来。(就给你加载那1个)aggeressiveLazyLoading是一个层级开关。
继续用那个雇员的例子来举例:
如果setting配置如下:
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="true"/>
</settings>
lazyLoadingEnabled开关开启后,如果你不去访问雇员任务和工卡信息的话,是不会加载的。
aggressiveLazyLoading值为true,将该层级带有延迟加载属性的对象完整加载。
因为体检表采用了鉴别器来获取数据,它将和实体(也就是雇员本身)同层级,所以将把体检表加载出来。
如果aggressiveLazyLoading值为false,体检表将不会加载出来。(任务信息和工卡当然也不会被加载出来了)
可是!这样也不是我们的需求呀,我们想得到基本信息和任务信息,显然着还没有满足我们的需求。
在MyBatis中使用fetchType属性,它可以处理全局定义无法处理的问题。他有两个值:
- eager:获取当前POJO后立即加载对应的数据。
- lazy:获取当前POJO后延迟加载对应的数据。
在任务的级联标签中,加入fetchType:
<collection property="employeeTaskList" column="id" fetchType="eager" select="com.learn.ssm.chapter5.mapper.EmployeeTaskMapper.getEmployeeTaskByEmpId"></collection>
这个时候将按照我们的要求加载数据,先加载雇员信息,然后加载雇员任务信息,fetchType属性会忽略全局配置项LazyLoadingEnabled和aggressiveLazyLoading。
总结:级联这个东西其实可用也可不用。要灵活使用,最后这个延迟加载的例子我没有附上代码,我觉得我写的还是能理解的。今天是第六天做笔记,作为19应届生,我其实看这本书的目的是为了差缺补漏,我之前接触SSM就是掌握了基本用法,对于配置和一些功能了解的不是全名。要是觉得我写的不是很清楚的知识点,还请自循搜索。
互联网轻量级框架SSM-查缺补漏第六天【级联+延迟加载特辑】的更多相关文章
- 互联网轻量级框架SSM-查缺补漏第八天(MyBatis插件plugin使用及原理)
简言:今天进行第八天的记录(只是写了八天).有的时候看的多,有的时候看的少,看的少的时候就攒几天一起写了.而今天这个插件我昨天写了一下午,下班没写完就回去了,今天把尾收了,再加上一个过程图方便下面原理 ...
- 互联网轻量级框架SSM-查缺补漏第一天
简言:工欲其事必先利其器,作为一个大四的准毕业生,在实习期准备抽空补一下基础.SSM框架作为互联网的主流框架,在会使用的基础上还要了解其原理,我觉得会对未来的职场会有帮助的.我特意的买了一本<J ...
- Java EE互联网轻量级框架整合开发— SSM框架(中文版带书签)、原书代码
Java EE互联网轻量级框架整合开发 第1部分 入门和技术基础 第1章 认识SSM框架和Redis 2 1.1 Spring框架 2 1.2 MyBatis简介 6 1.3 Spring MVC简介 ...
- Android查缺补漏(View篇)--自定义View利器Canvas和Paint详解
上篇文章介绍了自定义View的创建流程,从宏观上给出了一个自定义View的创建步骤,本篇是上一篇文章的延续,介绍了自定义View中两个必不可少的工具Canvas和Paint,从细节上更进一步的讲解自定 ...
- Android查缺补漏(IPC篇)-- Bundle、文件共享、ContentProvider、Messenger四种进程间通讯介绍
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8387752.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...
- Android查缺补漏(IPC篇)-- 款进程通讯之AIDL详解
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8436529.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...
- Android查缺补漏(线程篇)-- AsyncTask的使用及原理详细分析
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8515304.html 一.AsyncTask的使用 AsyncTask是一种轻 ...
- Android查缺补漏(IPC篇)-- 进程间通讯之AIDL详解
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8436529.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...
- CSS查缺补漏篇
前面的话:关于CSS,之前我已经做过一些基础的知识点介绍.CSS主要是用来给页面设置样式的,一般说来,在一个网站中,CSS应该独立封装在一个单独的.css外部文件中.样式的设置总体来说是不难的,但是需 ...
随机推荐
- Major compaction时的scan操作
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/u014393917/article/details/24419355 Major compactio ...
- 什么是cluster(群集)
一.群集的概念 在互联网应用中,随着站点对硬件性能.相应速度.服务稳定性.数据可靠性等要求越来越高,单台服务器力不从心,使用小型机或大型机价格还太昂贵,因此我们使用普通服务器来构建服务群集显然最划算. ...
- 量化分析获取数据的3种姿势(压箱底的神器Tushare)
自打入门量化分析起,就有相当部分的时间在与数据打交道,从数据的获取.清洗到使用,对分析而言既是繁琐的,也是必须的.有大牛曾经说,量化分析有8成的开发时间都在处理数据. 为了节省时间,将更多精力投入到策 ...
- vi基本状态
vi状态退出并保存:shift+ZZ vi readme.txt 进入VIM编辑器,可以新建文件也可以修改文件 如果这个文件,以前是没有的,则为新建,则下方有提示为新文件. 按ESC键 跳到命令模式, ...
- 高阶篇:5)仿真研究Simulation studies
本章目的:了解仿真,初步学会怎么应用仿真. 1.仿真的定义 仿真------就是用模型(物理模型或数学模型)代替实际系统进行实验和研究. 把实际系统建立成物理模型或数学模型进行研究,然后把对模型实 ...
- hdu1495 bfs搜索、模拟
大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为.因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶可乐,而且一定要喝的和seeyou一样多.但see ...
- 4G和有线网络的自动切换
最近项目有个需求,把移动服务器设备(Ubuntu14.04)安装4G模块,但如果连接有线时,可以自动切换到有线,以降低移动流量带来的费用. 以下是我实现的方法(经过一番痛苦的摸索) 1. 脚本/opt ...
- List<Type> 随机
public List<T> GetRandomList<T>(List<T> inputList){ //Copy to a array T[] copyArra ...
- 第八次 Scrum Meeting
第八次 Scrum Meeting 写在前面 会议时间 会议时长 会议地点 2019/4/12 22:00 20min 大运村1号楼6F 附Github仓库:WEDO 例会照片 工作情况总结(4.12 ...
- .net将List序列转为Json字符串
将List类型转化为Json,是我们平常开发时最常见的了.在使用中,有很多种方法,也可以使用. 第一种 第三方组件:Newtonsoft.Json.dll //转化成Json Newtonsoft.J ...