云博:Mybatis 壮大的效果集映射器resultMap

admin 6个月前 (05-24) 科技 56 0

1. 前言

resultMap 元素是 MyBatis 中最主要最壮大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下允许你举行一些 JDBC 不支持的操作。实际上,在为一些好比毗邻的庞大语句编写映射代码的时刻,一份 resultMap 能够取代实现一致功效的数千行代码。ResultMap 的设计头脑是,对简朴的语句做到零设置,对于庞大一点的语句,只需要形貌语句之间的关系就行了。

resultMap 可以将查询到的庞大数据,好比多张表的数据、一对一映射、一对多映射等庞大关系聚合到一个效果集当中。一样平常的营业开发通常都市和它打交道,今天就对 resultMap 举行一个详细解说。

2. resultMap

接下来我们来看看 resultMap 是若何举行映射的。

2.1 Getter/Setter 注入

我们声明一个数据库对应的实体类:

/**
 * @author felord.cn
 * @since 16:50
 **/
@Data
public class Employee implements Serializable {
    private static final long serialVersionUID = -7145891282327539285L;
    private String employeeId;
    private String employeeName;
    private Integer employeeType;
}

那么它对应的 resultMap 为:

<mapper namespace="cn.felord.mybatis.mapper.EmployeeMapper">
    <resultMap id="EmployeeMap" type="cn.felord.mybatis.entity.Employee">
        <id column="employee_id" property="employeeId"/>
        <result column="employee_name" property="employeeName"/>
        <result column="employee_type" property="employeeType"/>
    </resultMap>
</mapper>

我们来注释这些设置的属性:

<mapper namespace="全局唯一的名称空间">
    <resultMap id="本namespace下唯一" type="对应映射的实体">
        <id column="数据库主键字段名或者别名,使用它提高整体性能" property="对应实体属性"/>
        <result column="数据库字段名或者别名" property="对应实体属性"/>
    </resultMap>
</mapper>

以上方式是通过 GetterSetter 方式举行注入,也就是实体类必须有无参组织,对应属性必须有GetterSetter 方式。

2.2 组织注入

GetterSetter 方式举行注入是我们最常用的方式。然则 Mybatis 同样支持组织注入,若是 Employee 存在如下组织方式:

public Employee(String employeeId, String employeeName, Integer employeeType) {
    this.employeeId = employeeId;
    this.employeeName = employeeName;
    this.employeeType = employeeType;
}

那么对应的 resultMap 可以这样写:

<mapper namespace="cn.felord.mybatis.mapper.EmployeeMapper">
    <resultMap id="EmployeeMap" type="cn.felord.mybatis.entity.Employee">
        <constructor>
            <idArg column="employee_id" javaType="String"/>
            <arg column="employee_name" javaType="String"/>
            <arg column="employee_type" javaType="String"/>
        </constructor>
    </resultMap>
</mapper>

仔细的同砚发现这里并没有 property 属性,实在当你不声明property 属性时会凭据组织方式的参数列表顺序举行注入。

Mybatis 3.4.3 引入了 name 属性后我们就可以打乱 constructor 标签内的 arg 元素的顺序了。

<mapper namespace="cn.felord.mybatis.mapper.EmployeeMapper">
    <resultMap id="EmployeeConstructorMap" type="cn.felord.mybatis.entity.Employee">
        <constructor>
            <idArg column="employee_id" javaType="String" name="employeeId"/>
            <!-- 你可以不按参数列表顺序添加-->
            <arg column="employee_type" javaType="Integer" name="employeeType"/>
            <arg column="employee_name" javaType="String" name="employeeName"/>
        </constructor>
    </resultMap>
</mapper>

2.3 继续关系

Java 中的类一样,resultMap 也是可以继续的。下面是两个有继续关系的 Java 类:

那么 RegularEmployeeresultMap 就可以这么写:

<resultMap id="RegularEmployeeMap" extends="EmployeeMap" type="cn.felord.mybatis.entity.RegularEmployee">
    <result column="level" property="level"/>
    <result column="job_number" property="jobNumber"/>
    <association property="department" javaType="cn.felord.mybatis.entity.Department">
        <id column="department_id" property="departmentId"/>
        <result column="department_name" property="departmentName"/>
        <result column="department_level" property="departmentLevel"/>
    </association>
</resultMap>

Java 的继续关键字一样使用 extends 来举行继续。

2.4 一对一关联

明眼人会看出来 2.3 最后一个 resultMap 示例中有一个 association 标签。这个用来做什么用呢?打个譬喻,每一个正式员工 RegularEmployee会对应一个部门 Department,营业中会有把这种 一对一 关系查询出来的需求。以是 association 就派上了用场。

<resultMap id="RegularEmployeeMap" extends="EmployeeMap" type="cn.felord.mybatis.entity.RegularEmployee">
    <result column="level" property="level"/>
    <result column="job_number" property="jobNumber"/>
    <association property="属性名称" javaType="对应的Java类型">
        <id column="department_id" property="departmentId"/>
        <result column="department_name" property="departmentName"/>
        <result column="department_level" property="departmentLevel"/>
    </association>
</resultMap>

association 可以继续嵌套下去,有可能关联的工具中另有一对一关系。

2.5 一对多关联

有一对一关联,自然会有一对多关联。我们反客为主,一个部门有多个员工,我们可能需要查询一个部门的信息以及所有员工的信息装载到 DepartmentAndEmployeeList中去。

/**
 * @author felord.cn
 * @since 15:33
 **/
public class DepartmentAndEmployeeList extends Department {
    private static final long serialVersionUID = -2503893191396554581L;
    private List<Employee> employees;

    public List<Employee> getEmployees() {
        return employees;
    }

    public void setEmployees(List<Employee> employees) {
        this.employees = employees;
    }
}

我们可以在 resultMap 中使用 collection 关键字来处置一对多映射关系:

<resultMap id="DepartmentAndEmployeeListMap" extends="DepartmentMap"
           type="cn.felord.mybatis.entity.DepartmentAndEmployeeList">
    <collection property="employees" ofType="cn.felord.mybatis.entity.RegularEmployee">
        <id column="employee_id" property="employeeId"/>
        <result column="employee_name" property="employeeName"/>
        <result column="level" property="level"/>
        <result column="job_number" property="jobNumber"/>
    </collection>
</resultMap>

2.6 鉴别器

人人都知道,员工并不都是正式工,另有临时工。有时刻我们也期望能够将这两种区分开来,至于缘故原由你懂的。不深入讨论这个问题了。就这个需求而言我们的映射关系又庞大了,我们需要凭据某个条件来判断哪条数据是正式工,哪条数据是临时工,然后划分装入下面这个实体类的 regularEmployeestemporaryEmployees中。

/**
 * @author felord.cn
 * @since 15:33
 **/
public class DepartmentAndTypeEmployees extends Department {
    private static final long serialVersionUID = -2503893191396554581L;
    private List<RegularEmployee> regularEmployees;
    private List<TemporaryEmployee> temporaryEmployees;
    // getter setter
}

鉴别器(discriminator)元素就是被设计来应对这种情形的,另外也能处置其它情形,例如类的继续条理结构。 鉴别器的观点很好明白——它很像 Java 语言中的 switch 语句。

为此我们需要在 Employee 类中增添一个 int类型的 employeeType属性来区分正式工和临时工,其中 1代表正式工,而 0代表临时工。然后我们来编写查询 DepartmentAndTypeEmployeesresultMap :

<resultMap id="DepartmentAndTypeEmployeesMap" extends="DepartmentMap"
           type="cn.felord.mybatis.entity.DepartmentAndTypeEmployees">
    <collection property="regularEmployees" ofType="cn.felord.mybatis.entity.RegularEmployee">
        <discriminator javaType="int" column="employee_type">
            <case value="1">
                <id column="employee_id" property="employeeId"/>
                <result column="employee_name" property="employeeName"/>
                <result column="employee_type" property="employeeType"/>
                <result column="level" property="level"/>
                <result column="job_number" property="jobNumber"/>
            </case>
        </discriminator>
    </collection>
    <collection property="temporaryEmployees" ofType="cn.felord.mybatis.entity.TemporaryEmployee">
        <discriminator javaType="int" column="employee_type">
            <case value="0">
                <id column="employee_id" property="employeeId"/>
                <result column="employee_name" property="employeeName"/>
                <result column="employee_type" property="employeeType"/>
                <result column="company_no" property="companyNo"/>
            </case>
        </discriminator>
    </collection>
</resultMap>

切记一定是先声明 DepartmentAndTypeEmployees的两个 List ,然后在 collection 标签内部使用 discriminator 标签。

这里很容易犯以下错误,下面的写法虽然可以查询出数据然则知足不了上述需求

<resultMap id="DepartmentAndTypeEmployeesMap" extends="DepartmentMap"
               type="cn.felord.mybatis.entity.DepartmentAndTypeEmployees">
        <discriminator javaType="int" column="employee_type">
            <case value="1">
                <collection property="regularEmployees" ofType="cn.felord.mybatis.entity.RegularEmployee">
                    <!--省略-->
                </collection>
            </case>
            <case value="0">
                <collection property="temporaryEmployees" ofType="cn.felord.mybatis.entity.TemporaryEmployee">
                    <!--省略-->
                </collection>
            </case>
        </discriminator>
    </resultMap>

这种写法的意思是:当发现该条数据中 employee_type=1 时,就新建一个 List<RegularEmployee> 并把该条数据放进去,每次都市新建一个 List<RegularEmployee> ;当employee_type=0 时也一样。这样的话最终就会返回一个 List<DepartmentAndTypeEmployees>

3. 总结

resultMap 能够知足大部分营业场景对于数据映射的需求,今天我们对 MybatisresultMap 的一些用法举行了解说,实在 resultMap 另有一些有用的属性,基于篇幅的缘故原由这里不再解说,可阅读 Mybatis 官方文档。然则请注意虽然 resultMap 功效壮大,一定要合理使用,级联过于庞大会影响后期维护和性能。好比当一对多映射时,多的一方若是数据条数过大,会增添内存消耗和读写性能。希望今天的文章对你使用 resultMap 有所辅助,更实时的手艺资讯请多多关注:码农小胖哥

本次文章的 DEMO ,可关注民众号:Felordcn 回复 resultMap 获取。

关注民众号:Felordcn 获取更多资讯

小我私家博客:https://felord.cn

,

Sunbet

Sunbet 和 www.eyaeya.com强强联合,打造一站式全民直营平台,用资本、技术、服务在同行中获胜。Sunbet和EYAEYA网提供数十种线上纸牌、zhenren、电子游戏,致力打造公平公开公正的信誉平台。

皇冠APP声明:该文看法仅代表作者自己,与本平台无关。转载请注明:云博:Mybatis 壮大的效果集映射器resultMap

网友评论

  • (*)

最新评论

文章归档

站点信息

  • 文章总数:631
  • 页面总数:0
  • 分类总数:8
  • 标签总数:1165
  • 评论总数:240
  • 浏览总数:4482