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
: 表示需要以那一个字段中的数据作为查询条件
共有 0 条评论