美文网首页
mybatis学习之级联

mybatis学习之级联

作者: xm的那年 | 来源:发表于2019-05-13 23:01 被阅读0次
    image.png

    现在根据设计模型建立对应的pojo
    首先看体检表,由于体检表分为男性和女性,因此可以先设计一个父类,然后通过继承的方式来完成pojo

    package com.learn.ssm.chapter5.pojo;
    //体检表父类
    public  abstract class HealthForm {
    @Override
        public String toString() {
            return "HealthForm [id=" + id + ", empId=" + empId + ", heart=" + heart
                    + ", liver=" + liver + ", spleen=" + spleen + ", lung=" + lung
                    + ", kidney=" + kidney + ", note=" + note + "]";
        }
    private int id;
    private int 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 String getUterus() {
        return uterus;
    }
    
    
    
    @Override
    public String toString() {
        return super.toString()+    "FemaleHealthForm [uterus=" + uterus + "]";
    }
    
    
    
    public void setUterus(String uterus) {
        this.uterus = uterus;
    }
    

    男性体检表

    //男性体检表
    
    public class MaleHealthForm extends HealthForm {
        
    
        
        @Override
        public String toString() {
            return super.toString()+ "MaleHealthForm [prostate=" + prostate + "]";
        }
    
        private String prostate;
    
        public String getProstate() {
            return prostate;
        }
    
        public void setProstate(String prostate) {
            this.prostate = prostate;
        }
        
    

    接下来设计员工表,工牌表,和任务表的pojo

    //工牌表
    public class WorkCard {
    private int id;
    private int empId;
    private String realName;
    private String department;
    private String mobile;
    private String position;
    private String note;
    

    任务表

    public class Task {
    //任务表
        private int id;//编号
        @Override
        public String toString() {
            return "Task [id=" + id + ", title=" + title + ", context=" + context
                    + ", note=" + note + "]";
        }
        private String title;//任务标题
        private String context;//任务内容
        private String note;//备注
    

    还剩雇员表和雇员任务表,它们有一定的关联。先从雇员任务表下手,雇员任务表是通过任务编号(task_id)和任务一一对应。

    public class EmployeeTask {
    //雇员任务表
    /**
     * 雇员任务表示通过任务编号task_id来和任务表进行一一关联的,这里只考虑其自身和任务编号的关联
     * 
     */
        private int id;
        private int empId;
        private Task task=null;
        private String taskName;
        private String note;
    

    属性task是一个Task类的对象,由它进行关联任务信息。设置雇员表是关键。雇员根据性别分为男雇员和女雇员。它们会有不同体检表记录,但是无论男,女都有一个雇员类,它有两个子类,男雇员类和女雇员类。在mybatis中,有一个鉴别器,通过雇员的字段sex来判断决定使用哪一个具体的子类(MaleEmployee和FemaleEmployee)初始化对象,它与工牌表示一一对应的关联关系,对于雇员任务表示一对多的关系。
    雇员类POJO

    /***
    * 雇员父类
    * 雇员根据性别分为男雇员和女雇员,他们会有不同的体检表,但是都有一个父类表。有两个子类(MaleEmployee男雇员)(FemaleEmploee女雇员)
    * @author Administrator
    *
    */
    public class Employee {
    private int 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 class MaleEmployee extends Employee {
    private MaleHealthForm maleHealthForm=null;
    
    public MaleHealthForm getMaleHealthForm() {
        return maleHealthForm;
    }
    
    public void setMaleHealthForm(MaleHealthForm maleHealthForm) {
        this.maleHealthForm = maleHealthForm;
    }
    

    女雇员表POJO

    public class FemaleEmployee  extends Employee{
    //女性雇员表包括体检表
        private FemaleHealthForm femaleHealthForm=null;
    
        public FemaleHealthForm getFemaleHealthForm() {
            return femaleHealthForm;
        }
    
        @Override
        public String toString() {
            return "FemaleEmployee [femaleHealthForm=" + femaleHealthForm + "]";
        }
    
        public void setFemaleHealthForm(FemaleHealthForm femaleHealthForm) {
            this.femaleHealthForm = femaleHealthForm;
        }
    

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

    配置映射文件:
    配置映射文件是级联的核心内容,而对于Mapper对的接口就不再书里给出了,因为根据映射文件编写接口十分简单,从最简单的内容入手,最简单的内容无非是那些关联最少的POJO,根据图5-2所示,4个POJO中task和workcard是星湖独立的。所以他们的映射文件相对简单
    TaskMapper.xml&TaskMapper

    TaskMapper
    import com.learn.ssm.chapter5.pojo.Task;
    
    public interface TaskMapper {
    public Task getTask(int id);
    }
    
    
    TaskMapper.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.learn.ssm.chapter5.mapper.TaskMapper">
      <select  id="getTask" parameterType="int" resultType="task" >
      select id,title,context,note from t_task where id=#{id}
    
      </select>
      </mapper>
    

    workcard.xml&workcardMapper

    package com.learn.ssm.chapter5.mapper;
    
    import com.learn.ssm.chapter5.pojo.WorkCard;
    
    public interface WorkCardMapper {
    public WorkCard getWorkCardByEmpId(int 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.learn.ssm.chapter5.mapper.WorkCardMapper">
      <select id="getWorkCardByEmpId" parameterType="int"  resultType="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)和任务表关联。这是一个一对一级联的关系。使用了association元素。雇员任务表一对一级联
    雇员任务表一对一级联

    <?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.learn.ssm.chapter5.mapper.EmployeeTaskMapper"  >
      <resultMap type="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 
       association元素代表着一对一元素级联的开始,property属性代表着 映射到POJO属性上,select配置是命名空间+SQL.ID的形式,这样皆可以指定
       对应Mapper的SQL,mybatis就会通过对应的SQL将数据查询回来。column代表SQL的列,作为参数传递给select属性指定的SQL,如果是多个属性则用逗号隔开
       
       -->
       <association property="task" column="task_id" select="com.learn.ssm.chapter5.mapper.TaskMapper.getTask"
       />
      </resultMap>
      <select id="getEmployeeTaskByEmpId" parameterType="int"  resultMap="employeeTaskMap">
      select id,emp_id,task_name,task_id,note from t_employee_task
      where emp_id=#{empId}
      </select>
      
      </mapper>
    

    这里重点讲解一下association的几种不同用法
    <association property="task" column="task_id" select="com.learn.ssm.chapter5.mapper.TaskMapper.getTask" />
    第一种:
    association的元素代表着一对一级联的开始,property属性代表映射到POJO属性上,select配置是命名空间+SQL id的形式,这样就可以指向对应的mapper的SQL。MyBatis就会通过对应的SQL将数据查询回来。column代表SQL的列,用作参数传递给select属性指定的SQL,如果是多个参数,则需要使用逗号隔开。
    第二种:(不使用association标签的方式)

    <select id="getEmployeeWithDeptById0" resultMap="employeeDept0">
            select e.id id, e.name name, e.gender gender, e.email email, e.d_id departmentId, d.department_name departmentName
            from tbl_employee e, tbl_department d
            where d.id=e.d_id and e.id=#{id}
        </select>
    
    <!-- 第一种:利用resultMap进行级联查询,不使用association标签-->
        <resultMap id="employeeDept0" type="com.hly.entity.Employee">
            <id column="id" property="id"></id>
            <result column="name" property="name"></result>
            <result column="gender" property="gender"></result>
            <result column="email" property="email"></result>
            <result column="departmentId" property="department.id"></result>
            <result column="departmentName" property="department.departmentName"></result>
        </resultMap>
    

    第三种:使用association标签+javaType属性
    这种方法个人感觉跟第一种没有本质上的区别,还是一条sql语句对两张表进行关联查询,只不过在结果集映射的时候有一些不同,引入了association标签。可读性比较好,对象的结构关系相较于第一种方式来说更为清晰和明朗。
    sql部分,与第一种无异:

    <select id="getEmployeeWithDeptById" resultMap="employeeDept">
            select e.id id, e.name name, e.gender gender, e.email email, e.d_id departmentId, d.department_name departmentName
            from tbl_employee e, tbl_department d
            where d.id=e.d_id and e.id=#{id}
        </select>
    
    <!-- 第二种:利用resultMap进行级联查询,使用association标签 -->
        <resultMap id="employeeDept" type="com.hly.entity.Employee">
            <id column="id" property="id"></id>
            <result column="name" property="name"></result>
            <result column="gender" property="gender"></result>
            <result column="email" property="email"></result>
            <association property="department" javaType="com.hly.entity.Department">
                <id column="departmentId" property="id"></id>
                <result column="departmentName" property="departmentName"></result>
            </association>
        </resultMap>
    

    在级联元素中,association中是通过javaType的定义去声明实体映射,可以看到在这种写法中,通过association标签明确指定了department对象的类型,然后在这个association的子标签中对department对象进行结果映射

    而前面使用association标签+select属性
    这种方法就有意思了。与前面两种写法有比较大的不同,使用association的select标签,可以将原本两表联查的一条sql语句拆分为两条简单的sql语句。个人以为搞出这种方式的原因就是要支持级联查询的懒加载吧,这样可以很好的提升数据库的性能,毕竟只有在用到关联对象相关属性的时候,才会执行第二步的查询操作。这部分内容等到后面了解其原理,看过源码后再回来详细说明,在此留一个根。
    sql部分,这里就分两部分了。第一是在t_mployee_task表中,根据id查出对应的记录。第二步就是根据前一步中查出的task_id的值,在task表中查询对应的记录。注意这两个sql是分散在两个mapper.xml中的哈。
    association标签中有两个重要的属性,select是用来指定这个对象怎么去查,而column属性则是从第一步的查询结果中找出select所需的查询参数。

    再研究一下体检表,它能拆分为男性雇员表和女性雇员表,所以就有两个简单的映射器。

    <?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.learn.ssm.chapter5.mapper.MaleHealthFormMapper" >
      <select id="getMaleHealthForm" parameterType="int" resultType="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.learn.ssm.chapter5.mapper.FemaleHealthFormMapper" >
      <select id="getFemaleHealthForm" parameterType="int" resultType="femaleHealthForm" >
    select id, heart, liver, spleen, lung, kidney, uterus, note from
            t_female_health_form where emp_id = #{id}
      </select>
      </mapper>
      <!--  这两个映射器都是通过雇员编号找到对应的体检表的记录,为雇员查询是提供了查询体检表的SQL-->
      
    

    这两个映射器都是主要通过雇员编号找到对应的映射关系,为雇员查询是提供了查询的体检表SQL

    现在创建雇员的映射关系

    <?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.learn.ssm.chapter5.mapper.EmployeeMapper">
      <resultMap type="employee" id="employee">
      <id column="id" property="id" />
      <result column="real_name" property="realName"/>
      <!-- 第二种方式显式注册自定义typehandler -->
      <result column="sex" property="sex" typeHandler="com.learn.ssm.chapter4.typehandler.SexTypeHandler"/>
      <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  property="workCard" column="id"     select="com.learn.ssm.chapter5.mapper.WorkCardMapper.getWorkCardByEmpId"   >
      </association>
      
      <!-- 一对多的任务表,通过雇员任务表的雇员编号,返回任务list -->
      <collection property="employeeTaskList"  column="id" fetchType="eager"
      select="com.learn.ssm.chapter5.mapper.EmployeeTaskMapper.getEmployeeTaskByEmpId" 
       >
      </collection>
      
      
      <!--鉴别器  -->
      <discriminator javaType="int" column="sex">
      <case value="1"  resultMap="maleHealthFormMapper" />
      <case value="0"  resultMap="femaleHealthFormMapper" />
      </discriminator>
        </resultMap>
        
      <resultMap type="femaleEmployee"  
      id="femaleHealthFormMapper" extends="employee" >
      <!--男女性的雇员表继承了resultmap的id为employee,从类上来说也确实是继承  -->
      <association  property="femaleHealthForm" column="id" select="com.learn.ssm.chapter5.mapper.FemaleHealthFormMapper.getFemaleHealthForm"  />
      </resultMap>
      
      <resultMap  type="maleEmployee" id="maleHealthFormMapper" extends="employee" >
      <association  property="maleHealthForm" column="id" select="com.learn.ssm.chapter5.mapper.MaleHealthFormMapper.getMaleHealthForm"  />
      </resultMap>
      <!--工牌  -->
      <resultMap type="workCard" id="inworkcard"  >
    
      </resultMap>
      
      
      
      
    <select id="getEmployee" parameterType="int" resultMap="employee" >
    select id,real_name as realName,sex,birthday,mobile,email,position,note from t_employee where id=#{id}
    
    </select>
    

    注意:

    • associaation元素:对工牌进行一对一级联,这个在雇员任务表中已经分析过
    • collection元素 一对多级联,其select元素指向SQL,将通过column制定的SQL字段作为参数进行传递,然后就将结果返回给雇员POJO的属性employeeTaskList
    • discriminator元素,鉴别器,它的属性column代表着使用哪个字段来进行鉴别,这里的sex,而它的子元素case,则用于区分。类似于switch...case语句,而resultMap属性表示采用哪个ResultMap去映射,比如sex=1,则使用maleHealthFormMapper进行映射。没有合适的case,使用employee进行映射

    测试代码:

    public static void testGetEmployee() {
        Logger logger=Logger.getLogger(chapter5Main.class);
        SqlSession sqlSession = null;
        try {
            sqlSession = SqlSessionFactoryUtils.openSqlSession();
            EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
            Employee employee = employeeMapper.getEmployee2(1);
    //      EmployeeTaskMapper  employeeTaskMapper=sqlSession.getMapper(EmployeeTaskMapper.class);
    //      List<EmployeeTask> employeeTask=employeeTaskMapper.getEmployeeTaskByEmpId(2);
    //      TaskMapper taskmapper=sqlSession.getMapper(TaskMapper.class);
    //      Task task=taskmapper.getTask(1);
    //  logger.info(employee.getEmployeeTaskList());
    //      System.out.println(employee.getEmployeeTaskList());
            System.out.println(employee);
        
        } catch(Exception ex) {
            ex.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }
    
    

    延迟加载:

    配置项 作用 配置选项说明 默认值
    lazyLoadingEnabled 延迟加载的全局开关,当开启时,所有关联对象都会延迟加载,在特定关联关系中,可通过设置fetchType属性来覆盖该项的开关状态 true\false false
    aggressiveLazyLoading 当启用时,对任意延迟属性的调用会使带有延迟加载属性的对象完整加载;反之,则每种属性按需加载 true\false 版本之前为true,之后为false

    在mybatisconfig.xml中添加如下代码:
    <settings >

    <setting name="lazyLoadingEnabled" value="true" ></setting>

    <setting name="aggressiveLazyLoading" value="false" ></setting>
    </settings>
    选项lazyLoadingEnabled决定是否开启延迟加载,而选项aggressiveLazyLoading则控制是否采用层级加载,采用层级加载的话,所有关联的信息同个层级的都会被加载出来。比如查询雇员信息,属性中的task关联雇员任务表,属性workcard关联工卡等等,这些是处于同一个层级的情况下。
    我们要加载雇员信息只加载雇员任务信息,但是因为层级加载会把工牌信息也加载进来,为了处理这个问题我们可以使用fetchType的属性,它可以全局定义无法处理的问题。fetchType存在级联元素collection,association中。有两个值

    • eager,获得当前的POJO后,立即加载对应数据
    • lazy 获得当前POJO后延迟加载对应的数据

    现在全面学习另一种级联,这个方式完全可以消除N+1的问题,但是也引发其他的问题,首先SQL比较复杂,其次所需要的配置比之前复杂的多。再次一次性将所有的数据提取出来会造成内存的浪费,一般用于比较简单的且关联不多的场景

    <select id="getEmployee2"  parameterType="int"  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我们通过left join语句,将一个雇员模型信息所有的关联起来,这样便可以通过一条SQL将所有的信息都查询出来。对于列名做出了别名的处理。在mybatis中允许对这样的SQL进行配置,来完成级联。

    
    <resultMap id="employee2" type="employee" >
    <id column="id" property="id" />
      <result column="real_name" property="realName"/>
      <!-- 第二种方式显式注册自定义typehandler -->
      <result column="sex" property="sex" typeHandler="com.learn.ssm.chapter4.typehandler.SexTypeHandler"/>
      <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" />
       <!--在级联中assocaiation是通过javaType去声明实体映射,而collection则是通过ofType进行声明 -->
       <association property="workCard" column="id" javaType="workCard" >
       
       <id column="wc_id" property="id" ></id>
      <result column="wc_real_name" property="realName"  />
       <result column="id" property="empId"  />
        <result column="wc_department" property="department"  />
         <result column="wc_mbile" property="mobile"  />
          <result column="wc_position" property="position"  />
           <result column="wc_note" property="note"  />
      
       </association>
    
    <collection property="employeeTaskList"  ofType="employeeTask"   column="id">
    <id column="et_id" property="id"  />
    <result column="id" property="empId"  />
    <result column="et_task_name" property="taskName"  />
    <result column="et_note" property="note"  />
    <association property="task" javaType="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>
    <case value="0" resultMap="femaleHealthFormMapper2"></case>
    
    </discriminator>
    
    </resultMap>
    <resultMap type="maleEmployee" id="maleHealthFormMapper2" extends="employee2" >
    <association property="maleHealthForm" column="id" javaType="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="femaleEmployee" id="femaleHealthFormMapper2" extends="employee2" >
    <association property="femaleHealthForm" column="id" javaType="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>
    
    • 每一个级联元素(association,discriminator,collection)中属性的id的配置和POJO实体配置的id一一对应,形成级联,比如上述的SQL列et_task_id和task实体的id是对应的,这是级联的关键所在。
      -在级联元素上,association是通过javaType的定义声明实体映射,而collection则是使用ofType进行声明
    • discriminator元素定义使用何种具体的resultMap进行级联,这里通过sex列进行判定

    多对多级联

    在现实生活中,有一种多对多的级联,而在程序中多对多的级联往往会被拆分成两个一对多级联处理
    比如说:有许多用户,用户归属于一些角色,这样一个用户可以对应多个角色,而一个角色有可以由多个用户担当。
    角色POJO

    public class Role2 {
        private Long id;
        private String roleName;
        private String note;
        // 关联用户信息,一对多关联
        private List<User2> userList;
    
    

    用户POJO

    public class User2 {
        private Long id;
        private String userName;
        private String realName;
        private SexEnum sex;
        private String moble;
        private String email;
        private String note;
        // 对角色一对多关联
        private List<Role2> roleList;
    

    两个List类型的属性是专门做一对多级联的时候使用的,使用collection的元素去完成,得到两个mapper
    角色mapper.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.ssm.chapter5.mapper2.RoleMapper2">
        <resultMap type="com.ssm.chapter5.pojo2.Role2" id="roleMapper">
            <id column="id" property="id" />
            <result column="role_name" property="roleName" />
            <result column="note" property="note" />
            <collection property="userList" column="id" fetchType="lazy"
                select="com.ssm.chapter5.mapper2.UserMapper2.findUserByRoleId" />
        </resultMap>
    
        <select id="getRole" parameterType="long" resultMap="roleMapper">
            select id, role_name, note from t_role where id = #{id}
        </select>
    
        <select id="findRoleByUserId" parameterType="long" resultMap="roleMapper">
            select r.id, r.role_name, r.note from t_role r, t_user_role ur
            where r.id = ur.role_id and ur.user_id = #{userId}
        </select>
    </mapper>
    

    用户mapper.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.ssm.chapter5.mapper2.UserMapper2">
        <resultMap type="com.ssm.chapter5.pojo2.User2" id="userMapper">
            <id column="id" property="id" />
            <result column="user_name" property="userName" />
            <result column="real_name" property="realName" />
            <result column="sex" property="sex"
                typeHandler="com.ssm.chapter5.typeHandler.SexTypeHandler" />
            <result column="mobile" property="moble" />
            <result column="email" property="email" />
            <result column="position" property="position" />
            <result column="note" property="note" />
            <collection property="roleList" column="id" fetchType="lazy"
                select="com.ssm.chapter5.mapper2.RoleMapper2.findRoleByUserId" />
        </resultMap>
        <select id="getUser" parameterType="long" resultMap="userMapper">
            select id, user_name, real_name, sex, moble, email, note from t_user where
            id =#{id}
        </select>
        <select id="findUserByRoleId" parameterType="long" resultMap="userMapper">
            select u.id, u.user_name, u.real_name, u.sex, u.moble, u.email, u.note
            from
            t_user u , t_user_role ur where u.id = ur.user_id and ur.role_id =#{roleId}
        </select>
    </mapper>
    

    这里使用collection去关联,但是把fetchType设为laz,这样就能够进行延迟加载。
    测试代码

    public static void testUserRole() {
            SqlSession sqlSession = null;
            try {
                sqlSession = SqlSessionFactoryUtils.openSqlSession();
                RoleMapper2 roleMapper2 = sqlSession.getMapper(RoleMapper2.class);
                Role2 role2 = roleMapper2.getRole(1L);
                System.out.println(role2.getUserList().size());
                UserMapper2 userMapper2 = sqlSession.getMapper(UserMapper2.class);
                User2 user2 = userMapper2.getUser(1L);
                System.out.println(user2.getRoleList().size());
            } catch(Exception ex) {
                ex.printStackTrace();
            } finally {
                if (sqlSession != null) {
                    sqlSession.close();
                }
            }
        }
    

    一共有3条SQL被执行,因为在role.getUserList的方法中调用获取用户信息,所以延迟加载的语句被执行。

    相关文章

      网友评论

          本文标题:mybatis学习之级联

          本文链接:https://www.haomeiwen.com/subject/oqyraqtx.html