互联网轻量级框架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外部文件中.样式的设置总体来说是不难的,但是需 ...
随机推荐
- C# combobox手动赋值
DataTable dt = new DataTable(); dt.Columns.Add("REPAIR_VALUE"); dt.Columns.Add("REPAI ...
- 【SSO单点系列】开篇
年底将至,忙碌了好几个月的项目也接近尾声了.在这个项目中,由于要和其他外系统做单点登录(SSO),整合其他系统的功能.在网上查询了相关资料后,最终选取了Yale大学发起的一个开源项目 CAS, 作为项 ...
- mac配置虚拟机的net模式
a.点击PD的偏好设置进入 1)选择net模式(shared)(相当于VM的V8虚拟机) 2)勾选将mac连入当前的网络 3)勾选在网络系统偏好设置中显示网络连接 b.点击mac的网络系统偏好设置,可 ...
- c语言-求完全数的一个算法
#include<iostream> #include<math.h> using namespace std; int main() { int n,i,j=0,k,a[10 ...
- 简述Dubbo
目前处于实习期间,白天工作,网上自主学习.最近没事逛了一下当前招聘网上的招聘要求,其中dubbo这个关键字出现的比较多,因此花了点时间学习了一番,在这写写自己的理解. 说起Dubbo,得先聊聊RPC, ...
- JAVA数据结构--哈希表的实现(分离链接法)
哈希表(散列)的定义 散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度 ...
- SQL数据库Truncate的相关用法
数据库中 Truncate的用法:这个是删除表中的所有数据语法是 Truncate Table tablename他与delete的区别在于1 delete 可以有条件的删除 而truncate 是删 ...
- 第八次 Scrum Meeting
第八次 Scrum Meeting 写在前面 会议时间 会议时长 会议地点 2019/4/12 22:00 20min 大运村1号楼6F 附Github仓库:WEDO 例会照片 工作情况总结(4.12 ...
- sql developer链接不上oracle 报 The Network Adapter could not establish the connection
安装时候报 : Oracle 支持在具有 DHCP 分配的公共 IP 地址的系统上进行安装.但应使用静态 IP 地址来配置系统的主网络接口, 以便 Oracle 软件正常工作.有关在配置有 DHCP ...
- hadoop源码svn下载地址
1.apache开源框架