Java – Mybatis – resultMap配置

resultMap

为了解决<sql> 代码块不灵活的问题,mybatis 提供了字段映射标签,可以单独对某些字段进行映射。

<resultMap id="唯一性名称" type="绑定实现类"></resultMap>

当我们需要对某个数据库字段和实现类中的成员变量时,可以这样设置

<mapper namespace="cn.unsoft.Mybatis.Mapper.UserMapper">
    // 定义一个绑定 User 实现类的字段映射
    <resultMap id="userResultMap" type="User">
        // column 是数据库中的字段名
        // property 是要映射到实现类中的那个成员变量
        <result column="user_name" property="userName" />
        <result column="add" property="address" />
    </resultMap>
</mapper>

column : 设置映射关系中的字段名,必须是sql查询出的某个字段

property : 设置映射关系中的实体的属性名,必须是处理的实体类类型中的属性名(get set方法中的名称定义)

定义完resultMap 后,我们的 <select> 等标签的 resultType 实现类绑定要更改为resultMap

<mapper namespace="cn.unsoft.Mybatis.Mapper.UserMapper">
    // 定义一个绑定 User 实现类的字段映射
    <resultMap id="userResultMap" type="User">
        .....
    </resultMap>

    // 在resultType中需绑定类型为resultMap 的id值
    <select id="selectAll" resultType="userResultMap">
        select * from user where id = 1
    </select>

</mapper>

这样在执行时,mybatis会自动把数据库字段自动映射为指定的成员变量名

注意:resultMap 对于映身 主键 id 值和 非主键 是有不同的定义的

<id />:处理主键和实体类中属性的映射关系

<result /> : 处理普通字段和实体类中属性的映射关系

<association /> : 处理多对一

<collection /> : 处理一对多

 

多对一查询

Mybatis 中创建实体类对sql进行映射时,通常实体类所代表的是一个表的数据,实体类的一个对象是这个表查询的一条记录

但我们通常会使用联表查询的方式,连接多个表进行查询,其中一种即是多对一查询。

多对一指的是多个数据指向单个数据,如多个学生指向一个班级,或多个员工指向一个部门等。

举例:多个员工指向一个部门

// 员工实体类
public class Emp {

    // 员工id
    private Integer empId;
    // 员工姓名
    private String username;
    // 部门id
    private Integer deptId;

    // 部门实体类
    private Dept dept;
}

// 部门实体类
public class Dept {

    // 部门ID
    private Integer deptId;

    // 部门名称
    private String deptName;
}

从员工实体类中我们可以看到,包含另一个实体类Dept,但在Mybatis的Mapper.xml中需要对 Dept 实体类进行映射

// 通过层级映射
    <!--    设置resultMap类型映射-->
    <resultMap id="getAEmpInfoByIdResultMap" type="Emp">
        <id column="emp_id" property="empId"></id>
        <result column="username" property="username"></result>
        <result column="dept_id" property="deptId"></result>
        <result column="dept_id" property="dept.deptId"></result>
        <result column="dept_name" property="dept.deptName"></result>
    </resultMap>

    <select id="getAEmpInfoById" resultMap="getAEmpInfoByIdResultMap">
        select t_emp.* t_dept.*
        from t_emp
                 left join t_dept on
                     t_emp.dept_id = t_dept.dept_id
        where
            t_emp.emp_id = #{empId}
    </select>

通过层级方式进行对数据映射

 

Mybatis 考虑到这样的问题,所以也提供了一种专门处理多对一的自定义映射方案 <association> 标签

    <!--    设置resultMap类型映射-->
    <resultMap id="getAEmpInfoByIdResultMap" type="Emp">
        <id column="emp_id" property="empId"></id>
        <result column="username" property="username"></result>
        <result column="dept_id" property="deptId"></result>
        
<!--        通过association标签,实现处理多对一查询情况-->
        <association property="dept" javaType="Dept">
            <id column="dept_id" property="deptId"></id>
            <result column="depu_name" property="deptName"></result>
        </association>
    </resultMap>

    <select id="getAEmpInfoById" resultMap="getAEmpInfoByIdResultMap">
        select t_emp.* t_dept.*
        from t_emp
                 left join t_dept on
                     t_emp.dept_id = t_dept.dept_id
        where
            t_emp.emp_id = #{empId}
    </select>

association : 处理多对一映射关系(处理实体类类型的属性)

property : 设置需要处理映射关系的属性的属性名

javaType : 设置要处理的属性的类型。

 

分步查询

<association> 还支持分步查询方式,所谓分步查询,指的是先把员工查询出来,再通过员工中的 dept_id 取出来,再进行一次部门查询

// 创建 Dept 部门的查询Mapper接口,用于给 EmpMapper 调用
public interface DeptMapper {
    Dept selectDeptByDeptId(@Param("deptId") Integer dept_id);
}

// 创建 Dept 部门的查询Mapper映射文件
<mapper namespace="cn.unsoft.mybatis.mapper.DeptMapper">
    <select id="selectDeptByDeptId" resultType="Dept">
        select * from t_dept where dept_id = #{deptId}
    </select>
</mapper>

创建完对Dept 的映射文件后,可以在 EmpMapper 中调用这个映射进行查询

 

    <!--    设置resultMap类型映射-->
    <resultMap id="getAEmpInfoByIdResultMap" type="Emp">
        <id column="emp_id" property="empId"></id>
        <result column="username" property="username"></result>
        <result column="dept_id" property="deptId"></result>

<!--        通过association标签,实现处理多对一查询情况-->
        <association property="dept" select="cn.unsoft.mybatis.mapper.DeptMapper.selectDeptByDeptId" column="dept_id">
            <id column="dept_id" property="deptId"></id>
            <result column="depu_name" property="deptName"></result>
        </association>
    </resultMap>

    <select id="getAEmpInfoById" resultMap="getAEmpInfoByIdResultMap">
        select *
        from t_emp
        where t_emp.emp_id = #{empId}
    </select>

property : 设置需要处理映射关系的属性的属性名

select : 设置分步查询的sql的唯一标识

column : 将查询出的某个字段作为分步查询的sql的条件

 

分步查询中的延迟查询

在分步查询中,我们把多对一查询分解成多条sql语句进行查询,其中Mybatis支持延迟加载,实现性能优化。

延迟加载是指,当我们查询sql完成后,实体类映射查询结果的数据时,在分步查询的情况下,如果我们不访问特定字段时(多指第二步查询后的字段),Mybatis不会进行sql查询,而是当我们访问到特定字段时,Mybatis才进行查询。

举例:员工实体类和部门实体类

// 员工实体类
public class Emp {

    // 员工id
    private Integer empId;
    // 员工姓名
    private String username;
    // 部门id
    private Integer deptId;

    // 部门实体类
    private Dept dept;
}

其中员工实体类中包含了一个成员变量,是来自部门实体类Dept。

部门实体类Dept数据需通过二次sql查询后才有数据。详情请看上一章节【分步查询】

在开启延迟查询的情况下,如果我们并未访问到 Dept 实体类数据时,Mybatis不会进行第二步查询,仅当我们访问到 Dept 实体类数据时,Mybatis才会进行第二步查询。

        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        Emp emp = mapper.getAEmpInfoById(1);
        // 当我们只访问emp表中的数据时,Mybatis不进行第二步sql查询
        emp.getUsername();  // username 字段存在于 t_emp 表中,所以t_dept表不会被查询
        
        
        emp.getDept().getDeptName(); // deptName 字段存在于 t_dept 表中,直到被访问时,才会被查询

 

开启延迟查询

在 settings 中可以全局开启延迟查询:

    <settings>
<!--        开启全局延迟查询-->
<!--        官方解释:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。
            特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。-->
        <setting name="lazyLoadingEnabled" value="true" />
<!--        关闭按需加载,如果按需加载开启的话,访问任意属性都会触发查询-->
<!--        官方解释:开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 
            否则,每个延迟加载属性会按需加载(参考 lazyLoadTriggerMethods)-->
        <setting name="aggressiveLazyLoading" value="false" />
    </settings>

 

单独设定延迟查询

我们可以通下全局开启延迟查询来优化性能,但在某些查询上我们希望单独进行设置,那么可以在association 中使用 fetchType 属性来单解设置是否开启延迟查询

<association property="..." fetchType="lazy" select="..." column="...">
</association>

fetchType="eager" ==> 立即查询,不论后续是否会访问到该属性数据

fetchType="lazy"  ==> 延迟查询,只有当该属性被访问时,该属性对应的sql才会开始被查询

 

一对多查询

一对多查询是指一个实体类中所包含其它实体类的集合。

如:一个部门下有多个员工,或一个班级下有多个学生

举例:一个部门下有多个员工

public class Dept {

    // 部门ID
    private Integer deptId;

    // 部门名称
    private String deptName;
    
    // 部门下的员工
    private List<Emp> emps; 
}

Mapper接口中增加一个查询

 

public interface DeptMapper {
    /**
     * 
     * 通过查询部门id获得这个部门信息和包含在这个部门下的员工
     * @return
     */
    Dept getEmpsFromDeptId(@Param("deptId") Integer dept_id);
}

 

 

collection 标签

Mybatis 中提供 collection 标签,实现对一对多查询的支持

    <resultMap id="getEmpsFromDeptIdResultMap" type="Dept">
        <id column="dept_id" property="deptId"></id>
        <result column="dept_name" property="deptName"></result>

         使用collection 标签
        <collection property="emps" ofType="Emp">
            <id column="emp_id" property="empId"></id>
            <result column="username" property="username"></result>
            <result column="dept_id" property="deptId"></result>
        </collection>
    </resultMap>

    <select id="getEmpsFromDeptId" resultMap="getEmpsFromDeptIdResultMap">
        select *
        from t_dept
                 left join t_emp on t_dept.dept_id = t_emp.dept_id
        where t_dept.dept_id = #{deptId}
    </select>

property : 指用于存储集合的数据在实体类中的成员变量

ofType : 因为一对多,所以查询出来是多条数据,是一个集合,是什么类型的集合

 

分步查询

与多对一类似,一对多也可以使用多步查询的方式。

具体原理是,第一步先查询部门的信息,第二步再按照部门的id查询员工表中符合的记录,并把这些数据存到部门实体类的 emps 成员变量中。

在 EmpMapper 中创建一个专用于查询部门id的员工
public interface EmpMapper {
    List<Emp> getEmpsFromDeptId(@Param("deptId") Integer dept_id);
}

Mapper.xml 映射中创建查询sql
    <select id="getEmpsFromDeptId" resultType="Emp">
        select * from t_emp where dept_id = #{deptId}
    </select>

 

在部门映射中,定义collection标签

    <resultMap id="getEmpsFromDeptIdResultMap" type="Dept">
        <id column="dept_id" property="deptId"></id>
        <result column="dept_name" property="deptName"></result>
        <collection property="emps"
                    select="cn.unsoft.mybatis.mapper.EmpMapper.getEmpsFromDeptId"
                    column="dept_id"></collection>
    </resultMap>

    <select id="getEmpsFromDeptId" resultMap="getEmpsFromDeptIdResultMap">
        select *
        from t_dept
                 left join t_emp on t_dept.dept_id = t_emp.dept_id
        where t_dept.dept_id = #{deptId}
    </select>

property : 表示第二步查询后的数据存放在实体类的那个成员变量中

select : 表示委托查询Mapper的完整名称

column : 表示需要以那一个字段中的数据作为查询条件

如果您喜欢本站,点击这儿不花一分钱捐赠本站

这些信息可能会帮助到你: 下载帮助 | 报毒说明 | 进站必看

修改版本安卓软件,加群提示为修改者自留,非本站信息,注意鉴别

THE END
分享
二维码
打赏
海报
Java – Mybatis – resultMap配置
resultMap 为了解决<sql> 代码块不灵活的问题,mybatis 提供了字段映射标签,可以单独对某些字段进行映射。 <resultMap id="唯一性名称" type="绑定实现类"></resultMap> ……
<<上一篇
下一篇>>