ResultMap结果映射
ResultMap结果映射
起因
原因
当数据库字段名与实体类属性名不一致时,无法正确查询到对应的属性值。
解决办法
方法一: 为字段起别名
可以通过为字段起别名的方式,保证和实体类中的属性名保持一致
<!--List<Emp> getAllEmp();-->
<select id="getAllEmp" resultType="Emp">
select eid,emp_name empName,age,sex,email from t_emp
</select>方法二: 修改核心配置文件开启自动驼峰命名
可以在MyBatis的核心配置文件中的setting标签中,设置一个全局配置信息mapUnderscoreToCamelCase,
可以在查询表中数据时,自动将_类型的字段名转换为驼峰,
例如:字段名user_name,设置了mapUnderscoreToCamelCase,此时字段名就会转换为userName。
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>方式三: 使用ResulMap映射
resultMap 元素是 MyBatis 中最重要最强大的元素
ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
ResultMap 的优秀之处——你完全可以不用显式地配置它们。
环境准备
数据库准备
// 员工表
CREATE TABLE `t_emp` (
`emp_id` int NOT NULL AUTO_INCREMENT COMMENT '员工ID' ,
`emp_name` varchar(20) NULL COMMENT '员工姓名' ,
`age` int NULL COMMENT '员工年龄' ,
`sex` char(1) NULL COMMENT '性别' ,
`email` varchar(20) NULL COMMENT '邮箱' ,
`dept_id` int NULL COMMENT '部门ID' ,
PRIMARY KEY (`emp_id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8mb4 COLLATE=utf8mb4_general_ci
COMMENT='员工表';
CREATE TABLE `t_dept` (
`dept_id` int NOT NULL AUTO_INCREMENT COMMENT '部门ID' ,
`dept_name` varchar(20) NULL COMMENT '部门名称' ,
PRIMARY KEY (`dept_id`)
)ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4 COLLATE=utf8mb4_general_ci
COMMENT='部门表'
;
INSERT INTO t_emp (`emp_id`, `emp_name`, `age`, `sex`, `email`, `dept_id`) VALUES ('1', '张三', '22', '0', '123@qq.com', '1');
INSERT INTO t_emp (`emp_id`, `emp_name`, `age`, `sex`, `email`, `dept_id`) VALUES ('2', '李四', '33', '0', '123@qq.com', '1');
INSERT INTO t_emp (`emp_id`, `emp_name`, `age`, `sex`, `email`, `dept_id`) VALUES ('3', '王五', '42', '1', '123@qq.com', '3');
INSERT INTO t_emp (`emp_id`, `emp_name`, `age`, `sex`, `email`, `dept_id`) VALUES ('4', '赵六', '16', '0', '123@qq.com', '1');
INSERT INTO t_emp (`emp_id`, `emp_name`, `age`, `sex`, `email`, `dept_id`) VALUES ('5', '孙七', '62', '1', '123@qq.com', '2');
INSERT INTO t_emp (`emp_id`, `emp_name`, `age`, `sex`, `email`, `dept_id`) VALUES ('6', '钱八', '32', '0', '123@qq.com', '2');
INSERT INTO t_emp (`emp_id`, `emp_name`, `age`, `sex`, `email`, `dept_id`) VALUES ('7', '周九', '26', '0', '123@qq.com', '2');
INSERT INTO t_emp (`emp_id`, `emp_name`, `age`, `sex`, `email`, `dept_id`) VALUES ('8', '吴十', '29', '0', '123@qq.com', '2');
INSERT `t_dept` (`dept_id`, `dept_name`) VALUES ('1', '部门A');
INSERT `t_dept` (`dept_id`, `dept_name`) VALUES ('2', '部门B');
INSERT `t_dept` (`dept_id`, `dept_name`) VALUES ('3', '部门C');
INSERT `t_dept` (`dept_id`, `dept_name`) VALUES ('4', '部门D');
INSERT `t_dept` (`dept_id`, `dept_name`) VALUES ('5', '部门E');代码准备
创建实体类
package com.lgn.mybatis.pojo;
import lombok.Data;
@Data
public class Emp {
private Integer empId;
private String empName;
private Integer age;
private String sex;
private String email;
private Dept dept;
}package com.lgn.mybatis.pojo;
import lombok.Data;
import java.util.List;
@Data
public class Dept {
private Integer deptId;
private String deptName;
private List<Emp> empList;
}创建Mapper接口
分别创建DeptMapper和EmpMapper接口
创建Mapper映射文件
分别创建DeptMapper.xml 和 EmpMapper.xml
映射的使用
简单映射
public interface EmpMapper {
/**
* 查询所有员工(不包含部门信息)
* @return
*/
public List<Emp> getAllBaseEmp();
}<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lgn.mybatis.mapper.EmpMapper">
<resultMap id="getAllEmpResulMap" type="Emp">
<id property="empId" column="emp_id"></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>
<select id="getAllBaseEmp" resultMap="getAllEmpResulMap">
SELECT * FROM t_emp;
</select>
</mapper>
多对一映射
方式一:级联方式处理映射
- 映射文件
<resultMap id="getALlEmapJoinResultMap" type="Emp">
<id column="emp_id" property="empId"></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.deptId" column="dept_id"></result>
<result property="dept.deptName" column="dept_name"></result>
</resultMap>
<select id="getAllEmp" resultMap="getALlEmapJoinResultMap">
SELECT * FROM t_emp LEFT JOIN t_dept on t_emp.dept_id = t_dept.dept_id
</select>- 测试类
@Test
public void getAllEmpByDeptTest(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
List<Emp> allEmps = mapper.getAllEmpByDept(1);
allEmps.forEach(emp -> System.err.println(emp));
}- 测试结果

方式二:association处理映射
映射文件
<resultMap id="getAllEmpByDeptTwoResultMap" type="Emp"> <id column="emp_id" property="empId"></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="deptId" column="dept_id"></id> <result property="deptName" column="dept_name"></result> </association> </resultMap> <select id="getAllEmpByDeptTwo" resultMap="getAllEmpByDeptTwoResultMap"> SELECT * FROM t_emp LEFT JOIN t_dept on t_emp.dept_id = t_dept.dept_id WHERE t_emp.dept_id = #{dept_id} </select>测试类
@Test public void getAllEmpByDeptTwoTest(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); List<Emp> allEmps = mapper.getAllEmpByDeptTwo(1); allEmps.forEach(emp -> System.err.println(emp)); }测试结果

方式三:分步处理映射
通过分步查询,员工及所对应的部门信息
- 代码
第一步: 查询员工信息
// EmpMapper.java
Emp getEmpByIdWithStep(@Param("empId") Integer empId);// EmpMapper.xml
<resultMap id="getEmpByIdWithStepResultMap" type="Emp">
<id property="empId" column="emp_id"></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"
select="com.lgn.mybatis.mapper.DeptMapper.getDeptByIdWithStep"
column="dept_id">
</association>
</resultMap>
<select id="getEmpByIdWithStep" resultMap="getEmpByIdWithStepResultMap">
SELECT * FROM t_emp WHERE emp_id = #{empId}
</select>resultMap属性值说明
select:设置分布查询的sql的唯一标识(namespace.SQLId或mapper接口的全类名.方法名)
column:设置分步查询的条件
第二步:查询员工对应的部门信息
// DeptMapper.java
public Dept getDeptByIdWithStep(@Param("deptId") Integer deptId);// DeptMapper.xml
<resultMap id="getDeptByIdWithStepResultMap" type="dept">
<id property="deptId" column="dept_id"></id>
<result property="deptName" column="dept_name"></result>
</resultMap>
<select id="getDeptByIdWithStep" resultMap="getDeptByIdWithStepResultMap">
SELECT * FROm t_dept WHERE dept_id = #{deptId}
</select>测试
@Test public void getEmpByIdStepTest(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); Emp emp = mapper.getEmpByIdWithStep(1); System.err.println(emp); }
image-20230313091703284
一对多映射
方式一: collection处理映射
代码
// DeptMapper.java public Dept getDeptWithAllEmpByCollectionType(@Param("deptId") Integer deptId);// DeptMapper.xml <resultMap id="getAllEmpOfDeptCollectionResultMap" type="dept"> <id property="deptId" column="dept_id"></id> <result property="deptName" column="dept_name"></result> <collection property="empList" ofType="Emp"> <id property="empId" column="emp_id"></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> <select id="getDeptWithAllEmpByCollectionType" resultMap="getAllEmpOfDeptCollectionResultMap"> SELECT * FROM t_dept dept LEFT JOIN t_emp emp on dept.dept_id = emp.dept_id WHERE emp.dept_id = #{deptId} </select>测试
@Test public void getAllEmpOfDeptCollectionTest(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); DeptMapper mapper = sqlSession.getMapper(DeptMapper.class); Dept dept = mapper.getDeptWithAllEmpByCollectionType(1); System.err.println(dept); }
image-20230313093455740
方式二: 分步映射
代码
第一步: 查询部门信息
// DeptMapper.java public Dept getDeptByIdWithStep2(@Param("deptId") Integer deptId);// DeptMapper.xml <resultMap id="DeptAndEmpByStepOneResultMap" type="Dept"> <id property="deptId" column="dept_id"></id> <result property="deptName" column="dept_name"></result> <collection property="empList" select="com.lgn.mybatis.mapper.EmpMapper.getAllEmpByDeptId" column="dept_id"></collection> </resultMap> <select id="getDeptByIdWithStep2" resultMap="DeptAndEmpByStepOneResultMap"> select * from t_dept where dept_id = #{deptId} </select>第二步: 查询员工列表
// EmpMapper.java List<Emp> getAllEmpByDeptId(@Param("deptId") Integer deptId);// EmpMapper.xml <resultMap id="getAllEmpByDeptIdResulMap" type="Emp"> <id property="empId" column="emp_id"></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> <select id="getAllEmpByDeptId" resultMap="getAllEmpByDeptIdResulMap"> select * from t_emp where dept_id = #{deptId} </select>测试
@Test public void getAllEmpOfDeptStepTest(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); DeptMapper mapper = sqlSession.getMapper(DeptMapper.class); Dept dept = mapper.getDeptByIdWithStep2(1); System.err.println(dept); }

延迟加载
优点
先从单表查询,需要时再从关联表去关联查询,大大提高了数据库的性能,因为单表查询要比关联查询多张表速度要快。
配置方法
延迟加载多用在关联对象和集合中,association和collection具备设置延迟加载的功能
设置全局开关
在mybatis-config.xml中打开延迟加载的开关。配置完成后,所有的association和collection元素都生效
| 字段值 | 含义 | 字段值 | 默认值 |
|---|---|---|---|
| lazyLoadingEnabled | MyBatis是否开启延迟加载的总开关,当开启时,所有关联对象都会延迟加载。 特定关联关系中,可通过设置fetchType属性来覆盖该项的开关状态 | true /false | false |
| aggressiveLazyLoading | 开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 否则,每个延迟加载属性会按需加载 | true /false | false 在 3.4.1 及之前的版本默认值为 true |
<settings>
<!--开启全局的懒加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--是否立即加载,其实不用配置,默认为false-->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>配置单项开关
在指定的association和collection元素中配置fetchType属性。该属性配置将覆盖全局延迟设置.
| 字段值 | 含义 |
|---|---|
| eager | 立即加载 |
| lazy | 延迟加载 |
<resultMap id="DeptAndEmpByStepOneResultMap" type="Dept">
<id property="deptId" column="dept_id"></id>
<result property="deptName" column="dept_name"></result>
<collection property="empList"
select="com.lgn.mybatis.mapper.EmpMapper.getAllEmpByDeptId"
column="dept_id"
fetchType="lazy"
></collection>
</resultMap>代码测试
以修改单项配置开关为例,增加fetchType属性
修改配置
// DeptMapper.xml <resultMap id="DeptAndEmpByStepOneResultMap" type="Dept"> <id property="deptId" column="dept_id"></id> <result property="deptName" column="dept_name"></result> <collection property="empList" select="com.lgn.mybatis.mapper.EmpMapper.getAllEmpByDeptId" column="dept_id" fetchType="lazy" ></collection> </resultMap>测试
@Test public void lazySettingTypeTest() { SqlSession sqlSession = SqlSessionUtils.getSqlSession(); DeptMapper mapper = sqlSession.getMapper(DeptMapper.class); Dept dept = mapper.getDeptByIdWithStep2(1); System.err.println(dept.getDeptName()); System.err.println("================================"); dept.getEmpList().forEach(emp -> System.err.println(emp)); }
image-20230313101726467
注意:
通过懒加载查询完数据后,只需要确定SQL语句是否查询了对应的关联表即可。
不要输出对象,否则相当于使用了对象,就会进行对应的关联查询。
