MyBatis级联探讨

转自:http://blog.csdn.net/ykzhen2015/article/details/51161141

MyBatis级联探讨第一篇——概念和模型

原创 2016年04月26日 13:55:32

谈谈MyBatis级联,文章尽量具体一些。
1、概述
关于MyBatis级联有三种:
association  :一对一的关联
collection   : 一对多的关联
discriminator :鉴别器,
它可以用于鉴别是使用那个resultMapper,或者你暂时不能理解,可以暂时放放。后面我们会再谈。
MyBatis当前只能支持查询的级联,而不能支持新增,删除和更新这些操作。所以这里只会讨论查询的级联。当然首先谈论的是三种级联的用法,然后就是N+1问题,延迟加载的问题。
2、模型  
在讨论这些关联之前,我们需要先定义一个模型。


我们先简单描述一下模型:
我们有一个员工表,一个员工卡表,显然员工和员工卡是一对一的关系。
而员工有男性员工和女性员工所以他们的健康表是不一样的。
一个员工可以参与多个工程,所以有张员工工程表把,员工和工程关联起来了,员工和工程是一对多的关系。
下面笔者给出建表语句:


  1. CREATE TABLE t_employee   
  2. (  
  3.    id                 INT(20)              NOT NULL AUTO_INCREMENT,  
  4.    emp_name           VARCHAR(60)          NOT NULL,  
  5.   sex                TINYINT(2)              NOT NULL,  
  6.    PRIMARY KEY (id)  
  7. );  
  8.   
  9. CREATE TABLE t_employee_card   
  10. (  
  11.    id                 INT(20)              NOT NULL AUTO_INCREMENT,  
  12.    emp_id             INT(20)              NOT NULL,  
  13.    card_no            VARCHAR(20)          NOT NULL,  
  14.    PRIMARY KEY (id)  
  15. );  
  16.   
  17. CREATE TABLE t_employee_project   
  18. (  
  19.    id                 INT(20)              NOT NULL AUTO_INCREMENT,  
  20.    emp_id             INT(20),  
  21.    proj_id             INT(20),  
  22.    PRIMARY KEY (id)  
  23. );  
  24.   
  25. CREATE TABLE t_healthy_male   
  26. (  
  27.    id                 INT(20)              NOT NULL AUTO_INCREMENT,  
  28.    emp_id             INT(20),  
  29.    prostate           VARCHAR(60),  
  30.    PRIMARY KEY (id)  
  31. );  
  32.   
  33. CREATE TABLE t_healthy_remale   
  34. (  
  35.    id                 INTEGER              NOT NULL AUTO_INCREMENT,  
  36.    emp_id             INT(20),  
  37.    uterus             VARCHAR(60),  
  38.    PRIMARY KEY (id)  
  39. );  
  40.   
  41. CREATE TABLE t_project   
  42. (  
  43.    id                 INT(20)              NOT NULL AUTO_INCREMENT,  
  44.    proj_name          VARCHAR(60),  
  45.    PRIMARY KEY (id)  
  46. );  

3、定义POJO

让我们先定义POJO,如下:

  1. public class Employee implements Serializable {  
  2.   
  3.   
  4.     private static final long serialVersionUID = 5892612078624312365L;  
  5.   
  6.   
  7.     private Integer id;  
  8.     private String empName;  
  9.     private Integer sex;  
  10.     //员工卡,一对一关联  
  11.     private EmployeeCard employeeCard;  
  12.     //项目,一对多关联  
  13.     private List<Project> projectList;  
  14.     //########setter and getter############  
  15. }  
  16.   
  17.   
  18. public class MaleEmployee extends Employee implements Serializable {  
  19.   
  20.   
  21.   
  22.   
  23.     private static final long serialVersionUID = 6597520360502006892L;  
  24.   
  25.   
  26.   
  27.   
  28.     private List<String> prostateList;  
  29.   
  30.   
  31.     //########setter and getter############  
  32. }  
  33.   
  34.   
  35. public class FemaleEmployee extends Employee implements Serializable {  
  36.   
  37.   
  38.     private static final long serialVersionUID = -7565810909492919315L7;  
  39.   
  40.     private List<String> uterusList;  
  41.   
  42.     //########setter and getter############  
  43. }  
  44.   
  45.   
  46. public class EmployeeCard implements Serializable {  
  47.   
  48.     private static final long serialVersionUID = -7593225091990005041L;  
  49.   
  50.     private Integer empId;  
  51.     private Integer cardNo;  
  52.   
  53.     //########setter and getter############  
  54. }  
  55.   
  56.   
  57. public class Project implements Serializable {  
  58.   
  59.   
  60.     private static final long serialVersionUID = -7834541701010022018L;  
  61.   
  62.   
  63.     private Integer id;  
  64.     private String projName;  
  65.     //########setter and getter############  
  66. }  

除了Employee外,都是很简单的POJO。Employee其实也不复杂,Employee是基类,然后通过其派生一个男性一个女性的类,也不难理解。


下面,我们将就这三种级联展开更深一层的讨论。


MyBatis级联探讨第二篇——鉴别器(discriminator)

原创 2016年04月26日 14:11:59

1、概述:

鉴别器在于确定使用那个ResultMap来映射SQL查询语句,在实现中我们往往有一个基类,然后可以派生一些类。比如我们要选择一群人可以用List<Person>,然而Person里面有个性别sex,根据它还可以分为Male或者Female。鉴别器就要根据sex决定用Male还是用Female相关的Mapper进行映射。

这些话还是很抽象,不过说起鉴别器,语言真的不好用描述,不过不要紧,我们来看一个实例就豁然开朗了,我们知道在上篇中我们已经有了一个员工的POJO,然后继承这个POJO分成一个男性,一个女性的POJO。


2、实例:

当我们查询一批员工的时候,我们希望的是返回一个List<Employee>,而里面的元素根据性别(sex)自动匹配是MaleEmployee或者是FemaleEmployee,于是我们需要根据sex的值去决定使用MaleEmployee或者是FemaleEmployee的resultMap去映射,这便是鉴别器。

让我们来定义employ的mapper,xml代码如下:

  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <!DOCTYPE mapper  
  3.   PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
  4.   "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
  5. <mapper namespace="com.ykzhen2015.csdn.mapper.EmployeeMapper">  
  6.     <resultMap id="employeeMap" type="com.ykzhen2015.csdn.pojo.Employee">  
  7.         <id property="id" column="id" />  
  8.         <result property="empName" column="emp_name" />  
  9.         <result property="sex" column="sex" />  
  10.         <association property="employeeCard" column="id"  
  11.             select="com.ykzhen2015.csdn.mapper.EmployeeCardMapper.getEmployeeCardByEmpId" />  
  12.         <collection property="projectList" column="id"  
  13.             select="com.ykzhen2015.csdn.mapper.ProjectMapper.findProjectByEmpId" />  
  14.         <discriminator javaType="int" column="sex">  
  15.             <case value="1" resultMap="maleEmployeeMap" />  
  16.             <case value="2" resultMap="femaleEmployeeMap" />  
  17.         </discriminator>  
  18.     </resultMap>  
  19.   
  20.     <select id="getEmployee" parameterType="int" resultMap="employeeMap">  
  21.         select id, emp_name as empName, sex from t_employee where id =#{id}  
  22.     </select>  
  23.   
  24.     <resultMap id="maleEmployeeMap" type="com.ykzhen2015.csdn.pojo.MaleEmployee" extends="employeeMap">  
  25.         <collection property="prostateList" select="com.ykzhen2015.csdn.mapper.MaleEmployeeMapper.findProstateList" column="id" />  
  26.     </resultMap>  
  27.   
  28.     <resultMap id="femaleEmployeeMap" type="com.ykzhen2015.csdn.pojo.FemaleEmployee" extends="employeeMap">  
  29.         <collection property="uterusList" select="com.ykzhen2015.csdn.mapper.FemaleEmployeeMapper.findUterusList" column="id" />  
  30.     </resultMap>  
  31. </mapper>  


我们这里定义了employee的resultMap,它除了级联其他的和平时我们定义的没什么不一样。这里先不看别的级联,先看看鉴别器:<discriminator>元素,我们定义了用javaType说明它用的是整数作为参数,而column指的是SQL对应的列为sex。

那么<case>定义的是你的条件分支:

当sex=1时候,采用maleEmployeeMap;

当sex=2时,采用femaleEmployeeMap。

maleEmployeeMapfemaleEmployeeMap都继承了employeeMap,并且扩展了一个属性,它们用select属性,来定义如何取对应的属性数据。要记住下面这句话,后面我们还将讨论它:

这里使用了全限定路径,其次用column="id"作为参数传递,如果是多个参数的,需要用逗号分隔。



3、关联Mapper:

上面我们看到了我们使用了select关联其他的sql语句,而select里面给的就是一个全限定的路径。分别是:

com.ykzhen2015.csdn.mapper.MaleEmployeeMapper.findProstateList

com.ykzhen2015.csdn.mapper.FemaleEmployeeMapper.findUterusList

现在让我们看看这两个Mapper是怎么样的:

  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
  3.   "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
  4. <mapper namespace="com.ykzhen2015.csdn.mapper.MaleEmployeeMapper">  
  5.     <select id="findProstateList" parameterType="int" resultType="string">  
  6.         select prostate from t_healthy_male where emp_id = #{emp_id}  
  7.     </select>  
  8. </mapper>  
  9.   
  10.   
  11. <?xml version="1.0" encoding="UTF-8" ?>  
  12. <!DOCTYPE mapper  
  13.   PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
  14.   "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
  15. <mapper namespace="com.ykzhen2015.csdn.mapper.FemaleEmployeeMapper">  
  16.     <select id="findUterusList" parameterType="int" resultType="string">  
  17.         select uterus from t_healthy_female where emp_id = #{emp_id}  
  18.     </select>  
  19. </mapper>  
显然他们都比较简单,和我们定义的普通Mapper没什么区别。

记得上节中标红的这句话,就是两者的关联,这里两个select的全限定id,上节的这句话select属性是保持一致,而参数都是上节column表明的id,这样便建立了关系。

好,鉴别器就是那么简单,这样便能将两者关联在一起了。

MyBatis级联探讨第三篇——一对一和一对多

原创 2016年04月26日 14:40:45

除了鉴别器,显然MyBatis还有一对一,一对多的关联。而多对多的关联可以转变为两个一对多的关联,也十分简单,这里我们将讨论它们的使用。

继续我们上篇的代码,我们先看一下员工的Mapper:

  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <!DOCTYPE mapper  
  3.   PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
  4.   "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
  5. <mapper namespace="com.ykzhen2015.csdn.mapper.EmployeeMapper">  
  6.     <resultMap id="employeeMap" type="com.ykzhen2015.csdn.pojo.Employee">  
  7.         <id property="id" column="id" />  
  8.         <result property="empName" column="emp_name" />  
  9.         <result property="sex" column="sex" />  
  10.         <association property="employeeCard" column="id"  
  11.             select="com.ykzhen2015.csdn.mapper.EmployeeCardMapper.getEmployeeCardByEmpId" />  
  12.         <collection property="projectList" column="id"  
  13.             select="com.ykzhen2015.csdn.mapper.ProjectMapper.findProjectByEmpId" />  
  14.         <discriminator javaType="int" column="sex">  
  15.             <case value="1" resultMap="maleEmployeeMap" />  
  16.             <case value="2" resultMap="femaleEmployeeMap" />  
  17.         </discriminator>  
  18.     </resultMap>  
  19.   
  20.     <select id="getEmployee" parameterType="int" resultMap="employeeMap">  
  21.         select id, emp_name as empName, sex from t_employee where id =#{id}  
  22.     </select>  
  23.   
  24.     <resultMap id="maleEmployeeMap" type="com.ykzhen2015.csdn.pojo.MaleEmployee" extends="employeeMap">  
  25.         <collection property="prostateList" select="com.ykzhen2015.csdn.mapper.MaleEmployeeMapper.findProstateList" column="id" />  
  26.     </resultMap>  
  27.   
  28.     <resultMap id="femaleEmployeeMap" type="com.ykzhen2015.csdn.pojo.FemaleEmployee" extends="employeeMap">  
  29.         <collection property="uterusList" select="com.ykzhen2015.csdn.mapper.FemaleEmployeeMapper.findUterusList" column="id" />  
  30.     </resultMap>  
  31. </mapper>  

这里我们主要看到association和collection两个标签。

(1)对于association而言,我们在Employee 定义的时候属性employeeCard 是一个POJO对象。

而对于collection而言,我们在Employee定义的时候属性projectList是一个List列表。

这两个需要我们注意。

(2)其次值得我们注意的是他们之间的关联的SQL语句,都是需要用select属性去定义,这里我给的是全限定路径名称和鉴别器是一致的。

(3)再次我们进行关联的时候,往往需要传递参数,这里的column就是一个参数定义。


1、一对一关联(association)

还是老规矩,看看一对一关联的Mapper

  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
  3.   "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
  4. <mapper namespace="com.ykzhen2015.csdn.mapper.EmployeeCardMapper">  
  5.     <select id="getEmployeeCardByEmpId" parameterType="int" resultType="com.ykzhen2015.csdn.pojo.EmployeeCard">  
  6.          SELECT id, emp_id as empId, card_no as cardNo FROM t_employee_card WHERE emp_id = #{empId}  
  7.     </select>  
  8. </mapper>  

好的,这里很明显,上面红色字体谈论的select属性对应的就是这个SQL。其中column属性定义的参数就是这里的empId。这样便完成了一对一的关联。


2、一对多关联(collection)

看代码,上面的论述也比较清晰了,我也不再累赘了。

  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <!DOCTYPE mapper  
  3.   PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
  4.   "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
  5. <mapper namespace="com.ykzhen2015.csdn.mapper.ProjectMapper">  
  6.     <select id="findProjectByEmpId" parameterType="int" resultType="com.ykzhen2015.csdn.pojo.Project">  
  7.          SELECT a.id, a.proj_name as projName FROM t_project a, t_employee_project b  
  8.          where a.id = b.proj_id and b.emp_id = #{empId}  
  9.     </select>  
  10. </mapper>  

好这里我们就讲解完了,鉴别器,一对一,一对多的关联。但是这里还有一个大的问题没有处理(延迟加载问题),留待下章分解。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值