MyBatis自定义映射关系ResultMap
1、准备工作
数据库创建
填入数据
实体类创建
public class Emp {
private Integer eid;
private String empName;
private Integer age;
private String sex;
private String email;
public Emp(Integer eid, String empName, Integer age, String sex, String email) {
this.eid = eid;
this.empName = empName;
this.age = age;
this.sex = sex;
this.email = email;
}
public Emp() {
}
public Integer getEid() {
return eid;
}
public void setEid(Integer eid) {
this.eid = eid;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "Emp{" +
"eid=" + eid +
", empName='" + empName + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", email='" + email + '\'' +
'}';
}
}
public class Dept {
private Integer did;
private String dName;
public Dept() {
}
public Dept(Integer did, String dName) {
this.did = did;
this.dName = dName;
}
public Integer getDid() {
return did;
}
public void setDid(Integer did) {
this.did = did;
}
public String getdName() {
return dName;
}
public void setdName(String dName) {
this.dName = dName;
}
@Override
public String toString() {
return "Dept{" +
"did=" + did +
", dName='" + dName + '\'' +
'}';
}
}
可以看到数据库中t_emp中的字段emp_name与实体类中的empName属性并不一致,这是如果不经过处理,MyBatis取到该字段的值之后就不会自动赋值到实体类的empName属性。
为了解决字段名和属性名不一致的情况,有三种方法
-
为字段取别名,保持和属性名的一致
select eid,emp_name empName,age,sex,email from t_emp
-
设置全局配置,将_自动映射为驼峰
<setting name="mapUnderscoreToCamelCase" value="true"/>
-
使用resultMap自定义字段和属性的映射关系
<resultMap id="empResultMap" type="emp"> <id property="eid" column="eid"></id> <result property="empName" column="emp_name"></result> <result property="age" column="age"></result> <result property="sex" column="sex"></result> <result property="email" column="email"></result> </resultMap>
2、resultMap处理字段和属性的映射关系
要设置select标签中的resultMap属性,必须先用resultMap标签定义一个resultMap。
resultMap:设置自定义映射关系,有两个属性
- id:唯一标识,不能重复
- type:设置映射关系中的实体类类型
子标签:
- id:设置主键的映射关系
- result:设置普通属性的映射关系
id和resukt分别有两个相同属性:
- property:设置映射关系中的属性名,必须是resultMap标签中type属性所设置的实体类中的属性名
- column:设置映射关系中的字段名,必须是sql语句查询出的字段名
<resultMap id="empResultMap" type="emp">
<id property="eid" column="eid"></id>
<result property="empName" column="emp_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="email" column="email"></result>
</resultMap>
<!--List<Emp> getAllEmp();-->
<select id="getAllEmp" resultMap="empResultMap">
select * from t_emp
</select>
3、多对一映射处理
public class Emp {
private Integer eid;
private String empName;
private Integer age;
private String sex;
private String email;
private Dept dept;
//构造器和、get、set等
}
有三种方式
1>通过级联赋值处理多对一的关系
<resultMap id="EmpAndDeptResultMapOne" type="emp">
<id property="eid" column="eid"></id>
<result property="empName" column="emp_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="email" column="email"></result>
<result property="dept.did" column="did"></result>
<result property="dept.deptName" column="dept_name"></result>
</resultMap>
<!--Emp getEmpAndDept(@Param("eid") Integer eid);-->
<select id="getEmpAndDept" resultMap="EmpAndDeptResultMapOne">
select * from t_emp left join t_dept on t_emp.did = t_dept.did where t_emp.eid = #{eid}
</select>
2>通过association标签处理多对一的关系
- 属性
- property:需要处理多对一的映射关系的类的属性名
- javaType:该属性的类型
- 子标签
- id:设置主键的映射关系
- result:设置普通属性的映射关系
- property:设置映射关系中的属性名,必须是resultMap标签中type属性所设置的实体类中的属性名
- column:设置映射关系中的字段名,必须是sql语句查询出的字段名
<resultMap id="EmpAndDeptResultMapTwo" type="emp">
<id property="eid" column="eid"></id>
<result property="empName" column="emp_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="email" column="email"></result>
<association property="dept" javaType="Dept">
<id property="did" column="did"></id>
<result property="deptName" column="dept_name"></result>
</association>
</resultMap>
<!--Emp getEmpAndDept(@Param("eid") Integer eid);-->
<select id="getEmpAndDept" resultMap="EmpAndDeptResultMapTwo">
select * from t_emp left join t_dept on t_emp.did = t_dept.did where t_emp.eid = #{eid}
</select>
3>分步查询处理多对一的关系
此方法同样需要用到association标签,但是比方法2稍微麻烦一点,但有以下好处:
- 可以实现延迟加载。但是必须在核心配置文件中设置全局配置
- 代码可读性提高。
- 可以少写一些代码
-
在DeptMapper上创建一个方法查询某个部门,并在DeptMapper.xml中配置sql语句
/** * 通过分步查询查询员工及员工所对应的部门 * 分步查询第第一步:通过did查询员工所对应的部门 */ public Dept getEmpAndDeptByStepOne(@Param("did") Integer did);
<!--Dept getEmpAndDeptByStepTwo(@Param("did") Integer did)--> <select id="getEmpAndDeptByStepOne" resultType="dept"> select * from t_dept where did = #{did} </select>
-
在EmpMapper上创建一个方法查询员工信息,并在EmpMapper.xml中配置sql语句
/** * 通过分步查询查询员工及员工所对应的部门 * 分步查询第二步:查询员工 */ public Emp getEmpAndDeptByStepTwo(@Param("eid") Integer eid);
<!--Emp getEmpAndDeptByStepOne(@Param("eid") Integer eid)--> <select id="getEmpAndDeptByStepTwo" resultMap="EmpAndDeptByStepResultMap"> select * from t_emp where eid = #{eid} </select>
**注意:**该select标签中需要用resultMap属性引用配置好的EmpAndDeptByStepResultMap。
-
配置EmpAndDeptByStepResultMap
<resultMap id="EmpAndDeptByStepResultMap" type="emp"> <id property="eid" column="eid"></id> <result property="empName" column="emp_name"></result> <result property="age" column="age"></result> <result property="sex" column="sex"></result> <result property="email" column="email"></result> <!-- select:设置分步查询的sql唯一标识(namespace.SQLId或mapper接口的全类名.方法名) column:设置分步查询的条件 --> <association property="dept" select="mybatis.mapper.DeptMapper.getEmpAndDeptByStepOne" column="did"> <id property="did" column="did"></id> <result property="deptName" column="dept_name"></result> </association> </resultMap>
-
在测试方法中测试(只调用getEmpAndDeptByStepTwo方法即可)
**注意:**要配置分步查询,需要配置以下两个association标签的属性:
- select:设置分步查询的sql唯一标识(namespace.SQLId或mapper接口的全类名.方法名)
- column:设置分步查询的条件,也就是多对一的一
4、延迟加载
概念
也就是懒加载,一般情况下,在一个方法中有多条语句需要执行SQL语句从数据库中读取数据,虚拟机会一次性读取出来后存入内存,要查看就需要打印输出,而延迟加载就是当你需要通过打印输出访问某条SQL语句对应的查询结果时再调用该条SQL语句进行执行,并不会一次性将方法中的SQL语句全部执行,可以有效降低数据库的负担。
开启延迟加载
<!--开启延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
但有些功能不需要实现延迟加载,这时候需要找到映射文件里该功能的resultMap里的association标签中设置延迟加载不对该功能生效,如下
<association property="dept"
select="mybatis.mapper.DeptMapper.getEmpAndDeptByStepOne"
column="did"
fetchType="lazy">
<id property="did" column="did"></id>
<result property="deptName" column="dept_name"></result>
</association>
就是fetchType属性中的两个值eager和lazy
- eager:立即加载
- lazy:延迟加载
5、一对多映射处理
在Dept实体类中加入一个员工列表
public class Dept {
private Integer did;
private String deptName;
private List<Emp> emps;
//构造器,get,set,toString
}
MyBatis处理一对多的映射关系,有两种方法
1>通过collection标签处理一对多的关系
collection标签与association标签的使用类似,只不过javaType属性换成了ofType属性
/**
* 获取部门以及部门中作用的员工信息
*/
public Dept getDeptAndEmp(@Param("did") Integer did);
<resultMap id="DeptAndEmpResultMap" type="dept">
<id property="did" column="did"></id>
<result property="deptName" column="dept_name"></result>
<collection property="emps" ofType="emp">
<id property="eid" column="eid"></id>
<result property="empName" column="emp_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="email" column="email"></result>
</collection>
</resultMap>
<!--Dept getDeptAndEmp(@Param("did") String did)-->
<select id="getDeptAndEmp" resultMap="DeptAndEmpResultMap">
select * from t_dept left join t_emp on t_dept.did = t_emp.did where t_dept.did = #{did}
</select>
**注意:**ofType属性表示的是该集合中存储的数据类型
2>分步查询处理一对多的关系
-
在EmpMapper上创建一个方法查询某个部门对应的员工信息,并在EmpMapper.xml中配置sql语句
/** * 通过分步查询查询部门部门中对应的员工信息 * 分步查询第一步:查询员工 */ public List<Emp> getDeptAndEmpByStepOne(@Param("did") Integer did);
<!--List<Emp> getDeptAndEmpByStepOne(@Param("did") Integer did)--> <select id="getDeptAndEmpByStepOne" resultType="emp"> select * from t_emp where did = #{did} </select>
-
在DeptMapper上创建一个方法查询部门信息,并在DeptMapper.xml中配置sql语句
/** * 通过分步查询查询部门以及部门中对应的员工信息 * 分步查询第二步:查询部门信息 */ public Dept getDeptAndEmpByStepTwo(@Param("did") Integer did);
<!--Dept getDeptAndEmpByStepOne(@Param("did") Integer did)--> <select id="getDeptAndEmpByStepTwo" resultMap="DeptAndEmpByStepResultMap"> select * from t_dept where did = #{did} </select>
**注意:**该select标签中需要用resultMap属性引用配置好的DeptAndEmpByStepResultMap。
-
配置DeptAndEmpByStepResultMap
<resultMap id="DeptAndEmpByStepResultMap" type="dept"> <id property="did" column="did"></id> <result property="deptName" column="dept_name"></result> <!-- select:设置分步查询的sql唯一标识(namespace.SQLId或mapper接口的全类名.方法名) column:设置分步查询的条件 --> <collection property="emps" select="mybatis.mapper.EmpMapper.getDeptAndEmpByStepOne" column="did" fetchType="lazy"> <id property="eid" column="eid"></id> <result property="empName" column="emp_name"></result> <result property="age" column="age"></result> <result property="sex" column="sex"></result> <result property="email" column="email"></result> </collection> </resultMap>
**注意:**由于这里查询的员工信息用到的是did而不是eid,所以这里collection标签中的column属性值为did。
-
在测试方法中测试(只调用getDeptAndEmpByStepTwo方法即可)
**注意:**要配置分步查询解决一对多的映射,需要配置以下两个collection标签的属性:
- select:设置分步查询的sql唯一标识(namespace.SQLId或mapper接口的全类名.方法名)
- column:设置分步查询的条件,也就是多对一的一