王小码

导航

Mybaits(8)MyBatis级联-1

一、MyBatis级联概述

  级联是resultMap中的配置,比较复杂。级联是一个数据库实体的概念。比如角色需要存在用户与之对应,这样就有角色用户表,一个角色可能有多个用户,这是一对多级联,除此之外还有一对一级联。在MyBatis中还有一种级联叫鉴别级联,是一种可以选择具体实现类的的级联,例如查找雇员及体检表的信息,但是雇员有性别之分,根据性别不同,其体检表的项目也不同,那么体检表分为男性和女性两种,从而根据雇员性别区分关联。

  级联不是必须的,但是通过级联我们可以很快速的获取数据,如果级联过多也会增加系统的复杂度,同时降低系统的性能,所以当我们级联超过3层就不需要考虑使用级联,因为这样造成多个对象关联,程序的耦合和复杂难以维护,因此我们需要根据实际情况去判断并使用级联。

二、MyBatis级联分类

  MyBatis的级联分为3中:

(1)鉴别器:它是一个根据某些条件决定采用具体实现类级联的方案,比如体检表要根据性别去区分。

(2)一对一:比如学生证和学生就是一种一对一的级联,雇员和工牌表也是一对一的级联。

(3)一对多:比如班主任和学生就是一种一对多的级联。

需要注意的是MyBatis没有多对多级联,因为多对多的级联比较复杂,使用困难,而且可以通过两个一对多级联进行替换,所以MyBatis不支持多对多级联。

三、模型分析

(1)模型图

(2)sql语句

*==============================================================*/
/* 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 auto_increment,
   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 auto_increment,
   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;

 

 (3)测试案例构建

    前面我们已经知道搭建MyBatis工程基本步骤,现在我们直接进行代码填写。

第一步:创建实体类

    首先我们编写体检表实体类,上面的数据库设计我们知道体检表分为男女体检表,我们抽取公共字段建立体检表父类,男女体检表分别集成父类即可。

package com.xhbjava.domain;

/**
 * 体检表父类
 * 
 * @author Mr.wang
 * @date 2020年2月26日
 */
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 Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getEmpId() {
        return empId;
    }

    public void setEmpId(Long empId) {
        this.empId = empId;
    }

    public String getHeart() {
        return heart;
    }

    public void setHeart(String heart) {
        this.heart = heart;
    }

    public String getLiver() {
        return liver;
    }

    public void setLiver(String liver) {
        this.liver = liver;
    }

    public String getSpleen() {
        return spleen;
    }

    public void setSpleen(String spleen) {
        this.spleen = spleen;
    }

    public String getLung() {
        return lung;
    }

    public void setLung(String lung) {
        this.lung = lung;
    }

    public String getKidney() {
        return kidney;
    }

    public void setKidney(String kidney) {
        this.kidney = kidney;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }

}
package com.xhbjava.domain;

/**
 * 女性体检表
 * 
 * @author Mr.wang
 * @date 2020年2月26日
 */
public class FemaleHealthForm extends HealthForm {
    private String uterus;

    public String getUterus() {
        return uterus;
    }

    public void setUterus(String uterus) {
        this.uterus = uterus;
    }

}
package com.xhbjava.domain;

/**
 * 男性体检表
 * 
 * @author Mr.wang
 * @date 2020年2月26日
 */
public class MaleHealthForm extends HealthForm {
    private String prostate;

    public String getProstate() {
        return prostate;
    }

    public void setProstate(String prostate) {
        this.prostate = prostate;
    }

}

接下来我们完成员工表、工牌表和任务表的实体类,他们以员工表为核心,先完成工牌表和任务表。

package com.xhbjava.domain;

/**
 * 工牌实体类
 * 
 * @author Mr.wang
 * @date 2020年2月26日
 */
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 Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getEmpId() {
        return empId;
    }

    public void setEmpId(Long empId) {
        this.empId = empId;
    }

    public String getRealName() {
        return realName;
    }

    public void setRealName(String realName) {
        this.realName = realName;
    }

    public String getDepartment() {
        return department;
    }

    public void setDepartment(String department) {
        this.department = department;
    }

    public String getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    public String getPosition() {
        return position;
    }

    public void setPosition(String position) {
        this.position = position;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }

}
package com.xhbjava.domain;

/**
 * 任务
 * 
 * @author Mr.wang
 * @date 2020年2月26日
 */
public class Task {
    private Long id;
    private String title;
    private String context;
    private String note;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContext() {
        return context;
    }

    public void setContext(String context) {
        this.context = context;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }

}

然后还剩雇员表和雇员任务表,它们有一定的关联关系。先入手雇员任务表,它通过task_id和任务进行一对一关联。雇员对雇员任务关联由雇员去维护。

package com.xhbjava.domain;
/**
 * 雇员任务
 * @author Mr.wang
 *@date    2020年2月26日
 */
public class EmployeeTask {
    private Long id;
    private String empId;
    private Task task = null;
    private String taskName;
    private String note;
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getEmpId() {
        return empId;
    }
    public void setEmpId(String empId) {
        this.empId = empId;
    }
    public Task getTask() {
        return task;
    }
    public void setTask(Task task) {
        this.task = task;
    }
    public String getTaskName() {
        return taskName;
    }
    public void setTaskName(String taskName) {
        this.taskName = taskName;
    }
    public String getNote() {
        return note;
    }
    public void setNote(String note) {
        this.note = note;
    }
    

}

接着我们完成雇员实体类,通过分类雇员分为男女雇员,我们先建立雇员父类,其余继承父类即可。这里就是一个鉴别器,我们通过雇员性别来决定具体使用哪个子类初始化对象。

package com.xhbjava.domain;

import java.util.Date;
import java.util.List;

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> employeeTaskList = null;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getRealName() {
        return realName;
    }

    public void setRealName(String realName) {
        this.realName = realName;
    }

    public SexEnum getSex() {
        return sex;
    }

    public void setSex(SexEnum sex) {
        this.sex = sex;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPosition() {
        return position;
    }

    public void setPosition(String position) {
        this.position = position;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }

    public WorkCard getWorkcard() {
        return workcard;
    }

    public void setWorkcard(WorkCard workcard) {
        this.workcard = workcard;
    }

    public List<EmployeeTask> getEmployeeTaskList() {
        return employeeTaskList;
    }

    public void setEmployeeTaskList(List<EmployeeTask> employeeTaskList) {
        this.employeeTaskList = employeeTaskList;
    }

}
package com.xhbjava.enumeration;
/**
 * 性别枚举类
 * @author Mr.wang
 *@date    2020年2月26日
 */
public enum SexEnum {
    MALE(1, "男"), FEMALE(2, "女");

    private int id;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    SexEnum(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public static SexEnum getSexById(int id) {
        for (SexEnum sex : SexEnum.values()) {
            if (sex.getId() == id) {
                return sex;
            }

        }
        return null;

    }

}
package com.xhbjava.domain;

/**
 * 男雇员
 * 
 * @author Mr.wang
 * @date 2020年2月26日
 */
public class MaleEmployee extends Employee {
    private MaleHealthForm maleHealthForm = null;

    public MaleHealthForm getMaleHealthForm() {
        return maleHealthForm;
    }

    public void setMaleHealthForm(MaleHealthForm maleHealthForm) {
        this.maleHealthForm = maleHealthForm;
    }

}
package com.xhbjava.domain;

/**
 * 女雇员
 * 
 * @author Mr.wang
 * @date 2020年2月26日
 */
public class FemaleEmployee extends Employee {
    private FemaleHealthForm femaleHealthForm = null;

    public FemaleHealthForm getFemaleHealthForm() {
        return femaleHealthForm;
    }

    public void setFemaleHealthForm(FemaleHealthForm femaleHealthForm) {
        this.femaleHealthForm = femaleHealthForm;
    }

}

 第二步:编写持久层dao接口

我们先从简单的任务开始。

package com.xhbjava.dao;

import com.xhbjava.domain.Task;

/**
 * 任务接口
 * 
 * @author Mr.wang
 * @date 2020年2月26日
 */
public interface ITaskDao {
    public Task getTask(Long id);

}
<?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.xhbjava.dao.ITaskDao">
    <!-- 查询任务 -->
    <select id="getTask" parameterType="long"
        resultType="com.xhbjava.domain.Task">
        select id,title,context,note from t_task where id =#{id}
    </select>

</mapper>

配置SqlMapConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- 主配置文件 -->
<configuration>
    
    <properties resource="jdbcConfig.properties">
    </properties>
    <!-- 配置环境 -->
    <environments default="mysql">
        <!-- 配置mysql环境 -->
        <environment id="mysql">
            <!-- 配置事务类型 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置数据源 -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>
    </environments>
    <!-- 配置映射文件 -->
    <mappers>
        <package name="com.xhbjava.dao" />
    </mappers>
</configuration>

编写测试类进行测试

package com.xhbjava.test;

import java.io.IOException;
import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.xhbjava.dao.ITaskDao;
import com.xhbjava.domain.Task;

/**
 * 测试类
 * 
 * @author Mr.wang
 * @date 2020年1月7日
 */
public class MybatisJunitTest {
    InputStream in = null;
    SqlSessionFactory factory = null;
    SqlSession session = null;
    ITaskDao taskDao  = null;
    @Test
    public void testGetTask() {
        Task task  = taskDao.getTask(1l);
        System.out.println(task);
    }
    @Before
    public void init() {
        // 1.读取配置文件
        try {
            in = Resources.getResourceAsStream("SqlMapConfig.xml");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // 2.创建构建者
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        // 3.创建session工厂
        factory = builder.build(in);
        // 4.创建session对象
        session = factory.openSession(true);
        // 5.创建Dao的代理对象
        taskDao = session.getMapper(ITaskDao.class);
    }

    @After // 在测试方法执行完成之后执行
    public void destroy() throws Exception {
        
        // 7.释放资源
        session.close();
        in.close();
    }

}

 

继续添加工牌的持久层dao:

package com.xhbjava.dao;
/**
 * 工牌接口
 * @author Mr.wang
 *@date    2020年2月27日
 */

import com.xhbjava.domain.WorkCard;

public interface IWorkCardDao {
    public WorkCard getWorkCard(Long empId);

}
<?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.xhbjava.dao.IWorkCardDao">
    <!-- 查询工牌 -->
    <select id="getWorkCard" parameterType="Long"
        resultType="com.xhbjava.domain.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>

至此,我们的基本测试运行环境就搭建完成。项目完成结构如下图:

 

 四、一对一级联

我们完成了任务和工牌的构建,那么我们的雇员任务表是通过任务编号(task_id)和任务表进行关联,这是一对一的关联,使用assocation元素来完成。

(1)编写持久层dao层

package com.xhbjava.dao;

import com.xhbjava.domain.EmployeeTask;

/**
 * 员工任务
 * 
 * @author Mr.wang
 * @date 2020年2月27日
 */
public interface IEmployeeTaskDao {
    public EmployeeTask getEmployeeTaskByEmpId(Long empid);

}

(2)定义IEmployeeTaskDao.xml 文件中的查询配置信息

<?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.xhbjava.dao.IEmployeeTaskDao">
    <resultMap type="com.xhbjava.domain.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.xhbjava.dao.ITaskDao.getTask" />
    </resultMap>
    <select id="getEmployeeTaskByEmpId" resultMap="EmployeeTaskMap">
        select id, emp_id, task_name, task_id, note from t_employee_task
        where emp_id = #{empId}
    </select>

</mapper>

association元素代表一对一级联的开始,property属性代表映射到实体类EmployeeTask上。select配置的是命名空间+sql id形式,这样便可指向对于mapper的sql,MyBatis就会通过对于sql将数据查询回来。column代表sql的列,用作参数传递给select的属性指定的sql,如果是多个参数,逗号隔开就行。

(3)编写测试类进行测试

@Test
    public void getEmployeeTaskByEmpId() {
        EmployeeTask employeeTask  = employeeTaskDao.getEmployeeTaskByEmpId(1l);
        System.out.println(employeeTask);
    }

 (4)上面IEmployeeTaskDao.xml 我们也可以这样去配置

 

<?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.xhbjava.dao.IEmployeeTaskDao">
    <resultMap type="com.xhbjava.domain.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"
            javaType="com.xhbjava.domain.Task">
            <id column="id" property="id" />
            <result column="title" property="title" />
            <result column="context" property="context" />
            <result column="note" property="note" />
        </association>
    </resultMap>
    <select id="getEmployeeTaskByEmpId" resultMap="EmployeeTaskMap">
        select
        b.id,b.title,b.context,b.note id, emp_id, task_name, task_id, a.note
        from t_employee_task a,t_task b
        where a.task_id = b.id and emp_id =
        #{empId}
    </select>

</mapper>

 

 

posted on 2020-02-27 14:47  王小码  阅读(272)  评论(0编辑  收藏  举报