级联是一个数据库实体的概念。一对多的级联,一对多的级联,在MyBatis中还有一种被称为鉴别器的级联,它是一种可以选择具体实现类的级联。
  级联不是必须的,级联的好处是获取关联数据十分便捷,但是级联过多会增加系统的复杂度,同时降低系统的性能,此增彼减,所以当级联的层级超过3层时,就不要考虑使用级联了,因为这样会造成多个对象的关联,导致系统的耦合、复杂和难以维护。在现实的使用过程中,要根据实际情况判断是否需要使用级联。

MyBatis中的级联

MyBatis的级联分为3种。
•鉴别器(discriminator):它是一个根据某些条件决定采用具体实现类级联的方案,比如体检表要根据性别去区分。
•一对一(association):比如学生证和学生就是一种一对一的级联,雇员和工牌表也是一种一对一的级联。
•一对多(collection):比如班主任和学生就是一种一对多的级联。
值得注意的是,MyBatis没有多对多级联,因为多对多级联比较复杂,使用困难,而且可以通过两个一对多级联进行替换,所以MyBatis不支持多对多级联了。

  为了更好地阐述级联,先给出一个雇员级联模型,如图所示。

分析雇员级联模型:
•该模型是以雇员表为中心的。
•雇员表和工牌表是一对一的级联关系。
•雇员表和员工任务表是一对多的级联关系。
•员工任务表和任务表是一对一的级联关系。
•每个雇员都会有一个体检表,随着雇员表字段性别取值的不同,会有不同的关联表。
据此给出级联模型建表SQL,如代码清单所示。

DROP TABLE
IF EXISTS t_female_health_form; DROP TABLE
IF EXISTS t_male_health_form; DROP TABLE
IF EXISTS t_task; DROP TABLE
IF EXISTS t_work_card; DROP TABLE
IF EXISTS t_employee_task; DROP TABLE
IF EXISTS t_employee; /*==============================================================*/
/* Table: t_employee */
/*==============================================================*/
CREATE TABLE t_employee (
id INT (12) NOT NULL AUTO_INCREMENT,
real_name VARCHAR (60) NOT NULL,
sex INT (2) NOT NULL COMMENT '1 - 男 0 -女',
birthday DATE NOT NULL,
mobile VARCHAR (20) NOT NULL,
email VARCHAR (60) NOT NULL,
POSITION VARCHAR (20) NOT NULL,
note VARCHAR (256),
PRIMARY KEY (id)
); /*==============================================================*/
/* Table: t_employee_task */
/*==============================================================*/
CREATE TABLE t_employee_task (
id INT (12) NOT NULL,
emp_id INT (12) NOT NULL,
task_id INT (12) NOT NULL,
task_name VARCHAR (60) NOT NULL,
note VARCHAR (256),
PRIMARY KEY (id)
); /*==============================================================*/
/* Table: t_female_health_form */
/*==============================================================*/
CREATE TABLE t_female_health_form (
id INT (12) NOT NULL AUTO_INCREMENT,
emp_id INT (12) NOT NULL,
heart VARCHAR (64) NOT NULL,
liver VARCHAR (64) NOT NULL,
spleen VARCHAR (64) NOT NULL,
lung VARCHAR (64) NOT NULL,
kidney VARCHAR (64) NOT NULL,
uterus VARCHAR (64) NOT NULL,
note VARCHAR (256),
PRIMARY KEY (id)
); /*==============================================================*/
/* Table: t_male_health_form */
/*==============================================================*/
CREATE TABLE t_male_health_form (
id INT (12) NOT NULL AUTO_INCREMENT,
emp_id INT (12) NOT NULL,
heart VARCHAR (64) NOT NULL,
liver VARCHAR (64) NOT NULL,
spleen VARCHAR (64) NOT NULL,
lung VARCHAR (64) NOT NULL,
kidney VARCHAR (64) NOT NULL,
prostate VARCHAR (64) NOT NULL,
note VARCHAR (256),
PRIMARY KEY (id)
); /*==============================================================*/
/* Table: t_task */
/*==============================================================*/
CREATE TABLE t_task (
id INT (12) NOT NULL,
title VARCHAR (60) NOT NULL,
context VARCHAR (256) NOT NULL,
note VARCHAR (256),
PRIMARY KEY (id)
); /*==============================================================*/
/* Table: t_work_card */
/*==============================================================*/
CREATE TABLE t_work_card (
id INT (12) NOT NULL AUTO_INCREMENT,
emp_id INT (12) NOT NULL,
real_name VARCHAR (60) NOT NULL,
department VARCHAR (20) NOT NULL,
mobile VARCHAR (20) NOT NULL,
POSITION VARCHAR (30) NOT NULL,
note VARCHAR (256),
PRIMARY KEY (id)
); ALTER TABLE t_employee_task ADD CONSTRAINT FK_Reference_4 FOREIGN KEY (emp_id) REFERENCES t_employee (id)
ON DELETE RESTRICT ON UPDATE RESTRICT; ALTER TABLE t_employee_task ADD CONSTRAINT FK_Reference_8 FOREIGN KEY (task_id) REFERENCES t_task (id)
ON DELETE RESTRICT ON UPDATE RESTRICT; ALTER TABLE t_female_health_form ADD CONSTRAINT FK_Reference_5 FOREIGN KEY (emp_id) REFERENCES t_employee (id)
ON DELETE RESTRICT ON UPDATE RESTRICT; ALTER TABLE t_male_health_form ADD CONSTRAINT FK_Reference_6 FOREIGN KEY (emp_id) REFERENCES t_employee (id)
ON DELETE RESTRICT ON UPDATE RESTRICT; ALTER TABLE t_work_card ADD CONSTRAINT FK_Reference_7 FOREIGN KEY (emp_id) REFERENCES t_employee (id)
ON DELETE RESTRICT ON UPDATE RESTRICT;

建立POJO

  根据设计模型建立对应的POJO。首先看体检表,由于男性和女性的体检表有多个字段重复,于是可以先设计一个父类,然后通过继承的方式来完成POJO,体检表设计类图如图所示。

如图所示,其中MaleHealthForm和FemaleHealthForm是HealthForm的子类,由此可得3个关于体检表的POJO,如代码清单所示。

//体检表父类
public abstract class HealthForm {
private Long id;
private Long empId;
private String heart;
private String liver;
private String spleen;
private String lung;
private String kidney;
private String note;
} //女性体检表
public class FemaleHealthForm extends HealthForm {
private String uterus;
} //男性体检表
public class MaleHealthForm extends HealthForm {
private String prostate;
}

接下来设计员工表、工牌表和任务表的POJO,它们是以员工表作为核心的,先完成工牌表和任务表的POJO,如代码清单所示。

//工牌
public class WorkCard {
private Long id;
private Long empId;
private String realName;
private String department;
private String mobile;
private String position;
private String note;
} //任务
public class Task {
private Long id;
private String title;
private String context;
private String note;
}

还剩雇员表和雇员任务表,它们有一定的关联。先从雇员任务表入手,雇员任务表是通过任务编号(task_id)和任务进行一对一关联的,这里只考虑其自身和任务编号的关联,而雇员对它的关联则由雇员去维护,这样就可以得到雇员任务POJO,如代码清单所示。

//雇员任务
public class EmployeeTask {
private Long id;
private Long empId;
private Task task = null;
private String taskName;
private String note;
}

属性task是一个Task类对象,由它进行关联任务信息。设置雇员表是关键。雇员根据性别分为男雇员和女雇员,他们会有不同的体检表记录,但是无论男、女都是雇员,所以先建立一个雇员类(Employee)。它有两个子类:男雇员(MaleEmployee)和女雇员(FemaleEmployee)。在MyBatis中,这就是一个鉴别器,通过雇员类的字段性别(sex)来决定使用哪个具体的子类(MaleEmployee或者FemaleEmployee)初始化对象(Employee)。它与工牌表是一对一的关联关系,对于雇员任务表是一对多的关联关系,这样就可以得到3个类,如代码清单所示。

//雇员父类
public class Employee {
private Long id;
private String realName;
private SexEnum sex = null;
private Date birthday;
private String mobile;
private String email;
private String position;
private String note;
//工牌按一对一级联
private WorkCard workCard;
// 雇员任务,一对多级联
private List<EmployeeTask> emplyeeTaskList = null;
} //男雇员类
public class MaleEmployee extends Employee {
private MaleHealthForm maleHealthForm = null;
} //女雇员类
public class FemaleEmployee extends Employee {
private FemaleHealthForm femaleHealthForm = null;
}

MaleEmployee和FemaleEmployee都继承了Employee类,有着不同的体检表。Employee类是通过employeeTaskList属性和多个雇员任务进行一对多关联的,而工牌表是通过WorkCard进行一对一关联的,这样就完成了所有POJO的设计。

配置映射文件

<?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.xc.mapper.employee.TaskMapper"> <select id="getTask" parameterType="long" resultType="com.xc.pojo.employee.Task">
select id, title, context, note
from t_task
where id = #{id}
</select> </mapper> <?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.xc.mapper.employee.WorkCardMapper"> <select id="getWorkCardByEmpId" parameterType="long" resultType="com.xc.pojo.employee.WorkCard">
SELECT id, emp_id as empId, real_name as realName, department, mobile, position, note
FROM t_work_card
where emp_id = #{empId}
</select> </mapper> <?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.xc.mapper.employee.EmployeeTaskMapper"> <resultMap type="com.xc.pojo.employee.EmployeeTask" id="EmployeeTaskMap">
<id column="id" property="id"/>
<result column="emp_id" property="empId"/>
<result column="task_name" property="taskName"/>
<result column="note" property="note"/>
<association property="task" column="task_id" select="com.xc.mapper.employee.TaskMapper.getTask"/>
</resultMap> <select id="getEmployeeTaskByEmpId" parameterType="long" resultMap="EmployeeTaskMap">
select id, emp_id, task_name, task_id, note
from t_employee_task
where emp_id = #{empId}
</select> </mapper> <?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.xc.mapper.employee.MaleHealthFormMapper"> <select id="getMaleHealthForm" parameterType="long" resultType="com.xc.pojo.employee.MaleHealthForm">
select id,
heart,
liver,
spleen,
lung,
kidney,
prostate,
note
from t_male_health_form
where emp_id = #{id}
</select> </mapper> <?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.xc.mapper.employee.FemaleHealthFormMapper"> <select id="getFemaleHealthForm" parameterType="long" resultType="com.xc.pojo.employee.FemaleHealthForm">
select id,
heart,
liver,
spleen,
lung,
kidney,
uterus,
note
from t_female_health_form
where emp_id = #{id}
</select> </mapper> <?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.xc.mapper.employee.EmployeeMapper"> <resultMap type="com.xc.pojo.employee.Employee" id="employee">
<id column="id" property="id"/>
<result column="real_name" property="realName"/>
<result column="sex" property="sex" typeHandler="com.xc.util.typehandler.SexEnumTypeHandler"/>
<result column="birthday" property="birthday"/>
<result column="mobile" property="mobile"/>
<result column="email" property="email"/>
<result column="position" property="position"/>
<result column="note" property="note"/>
<!--association元素,对工牌进行一对一级联-->
<association property="workCard" column="id" select="com.xc.mapper.employee.WorkCardMapper.getWorkCardByEmpId"/>
<!--collection元素,一对多级联-->
<collection property="employeeTaskList" column="id"
select="com.xc.mapper.employee.EmployeeTaskMapper.getEmployeeTaskByEmpId"/>
<!--discriminator元素,鉴别器-->
<discriminator javaType="long" column="sex">
<case value="1" resultMap="maleHealthFormMapper"/>
<case value="2" resultMap="femaleHealthFormMapper"/>
</discriminator>
</resultMap> <resultMap type="com.xc.pojo.employee.FemaleEmployee" id="femaleHealthFormMapper" extends="employee">
<association property="femaleHealthForm" column="id"
select="com.xc.mapper.employee.FemaleHealthFormMapper.getFemaleHealthForm"/>
</resultMap> <resultMap type="com.xc.pojo.employee.MaleEmployee" id="maleHealthFormMapper" extends="employee">
<association property="maleHealthForm" column="id" select="com.xc.mapper.employee.MaleHealthFormMapper.getMaleHealthForm"/>
</resultMap> <select id="getEmployee" parameterType="long" resultMap="employee">
select id,
real_name as realName,
sex,
birthday,
mobile,
email,
position,
note
from t_employee
where id = #{id}
</select> </mapper>

另一种级联

MyBatis还提供了另一种级联方式,它是基于SQL表连接的基础上,进行再次设计的

   <!--MyBatis还提供了另一种级联方式,它是基于SQL表连接的基础上,进行再次设计的-->
<resultMap id="employee2" type="com.xc.pojo.employee.Employee">
<id column="id" property="id"/>
<result column="real_name" property="realName"/>
<result column="sex" property="sex" typeHandler="com.xc.util.typehandler.SexEnumTypeHandler"/>
<result column="birthday" property="birthday"/>
<result column="mobile" property="mobile"/>
<result column="email" property="email"/>
<result column="position" property="position"/>
<association property="workCard" javaType="com.xc.pojo.employee.WorkCard" column="id">
<id column="wc_id" property="id"/>
<result column="id" property="empId"/>
<result column="wc_real_name" property="realName"/>
<result column="wc_department" property="department"/>
<result column="wc_mobile" property="mobile"/>
<result column="wc_position" property="position"/>
<result column="wc_note" property="note"/>
</association>
<collection property="employeeTaskList" ofType="com.xc.pojo.employee.EmployeeTask" column="id">
<id column="et_id" property="id"/>
<result column="id" property="empId"/>
<result column="task_name" property="taskName"/>
<result column="note" property="note"/>
<association property="task" javaType="com.xc.pojo.employee.Task" column="et_task_id">
<id column="t_id" property="id"/>
<result column="t_title" property="title"/>
<result column="t_context" property="context"/>
<result column="t_note" property="note"/>
</association>
</collection>
<discriminator javaType="int" column="sex">
<case value="1" resultMap="maleHealthFormMapper2"/>
<case value="2" resultMap="femaleHealthFormMapper2"/>
</discriminator>
</resultMap>
<resultMap type="com.xc.pojo.employee.MaleEmployee" id="maleHealthFormMapper2" extends="employee2">
<association property="maleHealthForm" column="id" javaType="com.xc.pojo.employee.MaleHealthForm">
<id column="h_id" property="id"/>
<result column="h_heart" property="heart"/>
<result column="h_liver" property="liver"/>
<result column="h_spleen" property="spleen"/>
<result column="h_lung" property="lung"/>
<result column="h_kidney" property="kidney"/>
<result column="h_prostate" property="prostate"/>
<result column="h_note" property="note"/>
</association>
</resultMap>
<resultMap type="com.xc.pojo.employee.FemaleEmployee" id="femaleHealthFormMapper2" extends="employee">
<association property="femaleHealthForm" column="id" javaType="com.xc.pojo.employee.FemaleHealthForm">
<id column="h_id" property="id"/>
<result column="h_heart" property="heart"/>
<result column="h_liver" property="liver"/>
<result column="h_spleen" property="spleen"/>
<result column="h_lung" property="lung"/>
<result column="h_kidney" property="kidney"/>
<result column="h_uterus" property="uterus"/>
<result column="h_note" property="note"/>
</association>
</resultMap> <select id="getEmployee2" parameterType="long" resultMap="employee2">
select emp.id,
emp.real_name,
emp.sex,
emp.birthday,
emp.mobile,
emp.email,
emp.position,
emp.note,
et.id as et_id,
et.task_id as et_task_id,
et.task_name as et_task_name,
et.note as et_note,
if(emp.sex = 1, mhf.id, fhf.id) as h_id,
if(emp.sex = 1, mhf.heart, fhf.heart) as h_heart,
if(emp.sex = 1, mhf.liver, fhf.liver) as h_liver,
if(emp.sex = 1, mhf.spleen, fhf.spleen) as h_spleen,
if(emp.sex = 1, mhf.lung, fhf.lung) as h_lung,
if(emp.sex = 1, mhf.kidney, fhf.kidney) as h_kidney,
if(emp.sex = 1, mhf.note, fhf.note) as h_note,
mhf.prostate as h_prostate,
fhf.uterus as h_uterus,
wc.id wc_id,
wc.real_name wc_real_name,
wc.department wc_department,
wc.mobile wc_mobile,
wc.position wc_position,
wc.note as wc_note,
t.id as t_id,
t.title as t_title,
t.context as t_context,
t.note as t_note
from t_employee emp
left join t_employee_task et on emp.id = et.emp_id
left join t_female_health_form fhf on emp.id = fhf.emp_id
left join t_male_health_form mhf on emp.id = mhf.emp_id
left join t_work_card wc on emp.id = wc.emp_id
left join t_task t on et.task_id = t.id
where emp.id = #{id}
</select>

也会引发其他问题:首先,SQL会比较复杂;其次,所需要的配置比之前复杂得多;再次,一次性将所有的数据取出会造成内存的浪费。这样的复杂SQL,同时也会给日后的维护工作带来一定的困难,所以使用这样的级联,一般用于那些比较简单且关联不多的场景下。

mybatis 级联的更多相关文章

  1. (三)mybatis级联的实现

    mybatis级联的实现 开篇         级联有三种对应关系: 1.一对一(association):如学号与学生  2.一对多(collection):如角色与用户  3.多对多(discri ...

  2. Mybatis 级联查询 (一对多 )

    后台系统中 涉及到添加试卷 问题 答案的一个模块的.我需要通过试卷 查询出所有的试题,以及试题的答案.这个主要要使用到Mybatis的级联查询. 通过试卷 查询出与该试卷相关的试题(一对多),查询出试 ...

  3. Mybatis级联:关联、集合和鉴别器的使用

    Mybatis中级联有关联(association).集合(collection).鉴别器(discriminator)三种.其中,association对应一对一关系.collection对应一对多 ...

  4. mybatis级联

    mybatis中有时候表不能都分成单表进行查询,表之间会有联系,这时候需要将表进行级联 下面讲一下如何将mybatis中 的表进行级联.映射表关系如下 1:创建数据表 DROP TABLE IF EX ...

  5. Mybatis级联,使用JOIN和Associa,以及一些ID覆盖和自动变换。

    先说下坑,比如数据库的字段是 DW_ID  ,用generator讲mybatis自动转换的时候,会省略下表_变成dwId,所以我们之后自己手动设计的时候也尽量换成dwId: generate的myb ...

  6. mybatis级联查询,多对一查询问题

    在使用Mybatis进行多表级联查询时遇到了一个问题:查询结果只有一项,但正确结果是两项.经测试,SQL语句本身没有问题. 在SQL映射文件(XML)中: <!-- 级联查询数据 --> ...

  7. Mybaits(9)MyBatis级联-2

    一.鉴别器和一对多级联 1.完善体检表,分为男雇员体检和女雇员体检表 (1)持久层dao编写 package com.xhbjava.dao; import com.xhbjava.domain.Ma ...

  8. mybatis ---- 级联查询 一对多 (集合映射)

    关联有嵌套查询和嵌套结果两种方式,本文是按照嵌套结果这种方式来说明的 上一章介绍了多对一的关系,用到了<association></association>,这是一个复杂类型的 ...

  9. mybatis级联查询

    1.定义四个实体.User   Role    Privilege   Resource,他们之间的对于关系为 2.需求:我通过用户名username查找出该用户对应的角色以及角色对应的权限和资源 3 ...

随机推荐

  1. SpringMVC的数据效验

    Spring MVC本身没有数据校验的功能,它使用Hibernate的校验框架来完成. 1.导入pom节点 <!-- https://mvnrepository.com/artifact/org ...

  2. VSCompile

    VS2012加载失败 No exports were found that match the constraint 开始->运行->devenv.exe /resetuserdata-& ...

  3. RookeyFrame 自定义数据源 返回统计查询后的视图

    核心:对返回的数据进行重写 功能是这样的:上传淘宝后台的订单文件,将订单文件里面的数据导入到系统,对导入后的订单数据进行统计后再显示. Order_File:用来存上传的订单文件,格式是****.cs ...

  4. Linux下搭建iSCSI共享存储的方法 Linux-IO Target 方式 Debian9.5下实现

    iSCSI(internet SCSI)技术由IBM公司研究开发,是一个供硬件设备使用的.可以在IP协议的上层运行的SCSI指令集,这种指令集合可以实现在IP网络上运行SCSI协议,使其能够在诸如高速 ...

  5. Linux安装配置JDK与卸载

    最近在Linux系统部署门户,安装Oracle,导入dmp,JDK等等,遇到一大堆问题,解决后特有一番小小成就感,哇哈哈!在这里记录一下遇到问题: 官网下载JDK压缩包( .tar.gz ):http ...

  6. Ruby on Rails框架(1)-安装全攻略

    序 关于Rails的三句箴言 (1)DRY:Don't Repeat Yourself(不要重复你自己) rails的开发理念,不要用你的代码不停的重复,rails框架给开发者提供了一套非常完善的支持 ...

  7. rocketMq和kafka的架构区别

    概述 其实一直想写一篇rocketMq和kafka在架构设计上的差别,但是一直有个问题没搞明白所以迟迟没动手,今天无意中听人点播了一下似乎明白了这个问题,所以就有了这篇对比. 这篇博文主要讲清楚kaf ...

  8. VMware workstation虚拟机与真机之间复制文件

     首先选择导航栏的“虚拟机”选项,在下拉菜单中选择“安装VMware Tools” 弹出自动播放的选项,选择安装setup64.exe 开始安装VMware Tools,安装过程都保持默认即可,一直点 ...

  9. js 中数组对象的定义赋值 以及方法

    1.定义数组 var m=new Array(); var n=[]; 2.数组的赋值(两种) A. var m=new Array(2); 一个值表示数组length var m=new Array ...

  10. Java多线程相关的API方法以及作用摘要

    wait() 会让当前运行线程 阻塞,并释放对应的对象锁, 一般由当前线程持有的对象锁调用 x.wait(): 当前线程必须拥有此对象的monitor(即锁),才能调用此对象的wait()方法能让当前 ...