mybatis 級聯


 

  級聯是一個數據庫實體的概念。一對多的級聯,一對多的級聯,在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,同時也會給日后的維護工作帶來一定的困難,所以使用這樣的級聯,一般用於那些比較簡單且關聯不多的場景下。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM