Mybaits笔记框架:https://blog.csdn.net/qq_43751200/article/details/128154837
自定义映射resultMap
- 1. Mybatis环境搭建
- 2. 问题引入
- 3. 解决表中的字段名和对应类的属性名不一致问题
- 方式一: 为字段起别名,保持和属性名的一致
- 方式二:设置全局配置,将下划线_自动映射为驼峰
- 方式三:通过resultMap设置自定义的映射关系
- 4. 多对一映射处理
- 方式一:级联方式处理映射关系
- 方式二:使用association处理映射关系
- 方式三:分步查询
- 5. 一对多映射处理
- 方式一:使用collection处理映射关系
- 方式二:分布查询
- 6.延迟加载
1. Mybatis环境搭建
创建数据库表
-- 创建t_emp表
create table t_emp(
eid int NOT NULL PRIMARY KEY,
emp_name varchar(20),
age int,
sex char,
email varchar(20),
did int
)
-- 向t_emp表中插入数据
insert into t_emp(eid, emp_name, age, sex, email, did)
values(1, 'lsm', 23, '男', '1234@qq.com', 1),
(2, 'yxy', 23, '男', '1234@qq.com', 2),
(3, 'lxy1', 23, '男', '1234@qq.com', 3),
(4, 'yxy_lsm', 23, '男', '1234@qq.com', 2),
(5, 'lxy', 23, '男', '1234@qq.com', 1)
-- 创建t_dept表
create table t_dept(
did int,
dept_name varchar(20)
)
-- 向t_dept表中插入数据
insert into t_dept(did, dept_name) values(1, 'A'),(2, 'B'),(3, 'C')
在maven项目中创建对应的实体类(Empt类 和 Dept类)
Emp类
package com.atguigu.pojo;
/**
* @Author Mr.Lu
* @Date 2022/12/2 19:08
* @ClassName Emp
* @Version 1.0
*/
public class Emp {
private Integer eid;
// t_emp表该列名为emp_name
private String empName;
private Integer age;
private String sex;
private String email;
public Emp() {
}
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 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 + '\'' +
'}';
}
}
Dept类
package com.atguigu.pojo;
/**
* @Author Mr.Lu
* @Date 2022/12/2 19:07
* @ClassName Dept
* @Version 1.0
*/
public class Dept {
private Integer did;
// t_dept表该列名为dept_name
private String deptName;
public Dept() {
}
public Dept(Integer did, String deptName) {
this.did = did;
this.deptName = deptName;
}
public Integer getDid() {
return did;
}
public void setDid(Integer did) {
this.did = did;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
@Override
public String toString() {
return "Dept{" +
"did=" + did +
", deptName='" + deptName + '\'' +
'}';
}
}
项目结构
2. 问题引入
DeptMapper接口
/**
* 获取表t_Emp的所有信息
* @return
*/
List<Emp> getEmpAll();
DeptMapper接口对应的DeptMapper.xml配置文件
<!--List<Emp> getEmpAll();-->
<select id="getEmpAll" resultType="Emp">
select * from t_emp
</select>
测试方法
@Test
public void testGetEmpAll(){
SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSession();
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
List<Emp> empAll = empMapper.getEmpAll();
for(Emp emp : empAll){
System.out.println(emp);
}
sqlSession.close();
}
问题描述:经过上图发现empName对应的值都为null,但是t_emp表中的emp_name是存在值的,这是为什么呐?。经过分析产生这种情况的原因在于表中的字段名和对应类的属性名不一致,这个要如何解决呐?
3. 解决表中的字段名和对应类的属性名不一致问题
方式一: 为字段起别名,保持和属性名的一致
在EmpMapper.xml中为字段起别名
<!--解决实体类中的属性名称和对应表中的列名不一致问题,方式1: 起别名-->
<select id="getEmpAll" resultType="Emp">
select eid, emp_name empName, age, sex, email from t_emp
</select>
测试方法测试:
方式二:设置全局配置,将下划线_自动映射为驼峰
可以在MyBatis的核心配置文件中的setting
标签中,设置一个全局配置信息mapUnderscoreToCamelCase
,可以在查询表中数据时,自动将_类型的字段名转换为驼峰,例如:字段名user_name,设置了mapUnderscoreToCamelCase
,此时字段名就会转换为userName。
在mybatis-config.xml核心配置文件中加入对应的setting
标签
<!--设置Mybatis的全局配置-->
<settings>
<!--将下划线_自动映射为驼峰,emp_name : empName -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
测试方法测试:
方式三:通过resultMap设置自定义的映射关系
-
resultMap:设置自定义映射
-
属性:
-
id:表示自定义映射的唯一标识,不能重复
-
type:查询的数据要映射的实体类的类型, 例如User、Emp等实体类型
-
子标签:
-
id:设置主键的映射关系
-
result:设置普通字段的映射关系
-
子标签属性:
-
property:设置映射关系中实体类中的属性名
-
column:设置映射关系中表中的字段名
-
-
-
若字段名和实体类中的属性名不一致,则可以通过resultMap设置自定义映射,即使字段名和属性名一致的属性也要映射,也就是全部属性都要列出来
<!--解决实体类中的属性名称和对应表中的列名不一致问题,方式3: resultMap方式-->
<resultMap id="empResultMap" type="Emp">
<id property="eid" column="eid"/>
<result property="empName" column="emp_name"/>
<result property="age" column="age"/>
<result property="sex" column="sex"/>
<result property="email" column="email"/>
</resultMap>
<select id="getEmpAll" resultMap="empResultMap">
select * from t_emp
</select>
测试方法测试:
4. 多对一映射处理
多个员工对应一个部门:多对一
一个部门对应多个员工:一对多
需求:查询员工信息以及员工所对应的部门信息
public class Emp {
private Integer eid;
private String empName;
private Integer age;
private String sex;
private String email;
private Dept dept; // 该员工所属的部门
//...构造器、get、set方法等
}
方式一:级联方式处理映射关系
EmpMapper接口
/**
* 根据t_emp表的eid查询emp和dept表,最后封装成Emp对象返回
* @param eid
* @return
*/
Emp getEmpAndDeptById(Integer eid);
EmpMapper接口对应的EmpMapper.xml配置文件
<!-- 处理多对一映射关系方式1: 使用级联属性赋值 -->
<resultMap id="empAndDeptResultMap" type="Emp">
<id property="eid" column="eid"/>
<result property="empName" column="emp_name"/>
<result property="empName" column="emp_name"/>
<result property="age" column="age"/>
<result property="sex" column="sex"/>
<result property="email" column="email"/>
<!--下面两行的column对应部门表t_dept的字段名称-->
<result property="dept.did" column="did"/>
<result property="dept.deptName" column="dept_name"/>
</resultMap>
<!--Emp getEmpAndDeptById(Integer eid);-->
<select id="getEmpAndDeptById" resultMap="empAndDeptResultMap">
select * from t_emp left join t_dept on t_emp.did = t_dept.did where t_emp.eid = #{eid}
</select>
测试方法
@Test
public void testGetEmpAndDeptById(){
SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSession();
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = empMapper.getEmpAndDeptById(1);
System.out.println(emp);
sqlSession.close();
}
方式二:使用association处理映射关系
EmpMapper接口
/**
* 根据t_emp表的eid查询emp和dept表,最后封装成Emp对象返回
* @param eid
* @return
*/
Emp getEmpAndDeptById(Integer eid);
EmpMapper接口对应的EmpMapper.xml配置文件
<!-- 处理多对一映射关系方式2: 使用association处理映射关系-->
<resultMap id="empAndDeptResultMap" type="Emp">
<id property="eid" column="eid"/>
<result property="empName" column="emp_name"/>
<result property="empName" column="emp_name"/>
<result property="age" column="age"/>
<result property="sex" column="sex"/>
<result property="email" column="email"/>
<!--
association: 处理多对一的映射关系
property: 需要处理多一的映射关系的属性名
javaType: 该属性的类型
-->
<association property="dept" javaType="Dept">
<id property="did" column="did"/>
<result property="deptName" column="dept_name"/>
</association>
</resultMap>
<!--Emp getEmpAndDeptById(Integer eid);-->
<select id="getEmpAndDeptById" resultMap="empAndDeptResultMap">
select * from t_emp left join t_dept on t_emp.did = t_dept.did where t_emp.eid = #{eid}
</select>
测试方法
@Test
public void testGetEmpAndDeptById(){
SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSession();
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = empMapper.getEmpAndDeptById(3);
System.out.println(emp);
sqlSession.close();
}
方式三:分步查询
查询员工信息
EmpMapper接口
/**
* 分布查询,员工及所对应的部门信息
* 查询员工信息
* @param eid
* @return
*/
Emp getEmpAndDeptByStepOne(@Param("eid") Integer eid);
EmpMapper接口对应的EmpMapper.xml配置文件
- select:设置分布查询的sql的唯一标识(namespace.SQLId或mapper接口的全类名.方法名)
- column:设置分步查询的条件
<resultMap id="getEmpAndDeptByStepOneResultMap" type="Emp">
<id property="eid" column="eid"/>
<result property="empName" column="emp_name"/>
<result property="age" column="age"/>
<result property="sex" column="sex"/>
<result property="email" column="email"/>
<!--
select:设置分布查询的sql的唯一标识(namespace.SQLId或mapper接口的全类名.方法名)
column:设置分步查询的条件
-->
<association property="dept"
select="com.atguigu.mapper.DeptMapper.getEmpAndDeptByStepTwo"
column="did"/>
</resultMap>
<!-- Emp getEmpAndDeptByStepOne(@Param("eid") Integer eid);-->
<select id="getEmpAndDeptByStepOne" resultMap="getEmpAndDeptByStepOneResultMap">
select * from t_emp where eid = #{eid}
</select>
查询部门信息
DeptMapper接口
/**
* 根据did查询部门信息
* @param did
* @return
*/
Dept getEmpAndDeptByStepTwo(@Param("did") Integer did);
DeptMapper接口对应的DeptMapper.xml配置文件
<resultMap id="getEmpAndDeptByStepTwoResultMap" type="Dept">
<id property="did" column="did"/>
<result property="deptName" column="dept_name"/>
</resultMap>
<!-- Dept getEmpAndDeptByStepTwo(@Param("did") Integer did);-->
<select id="getEmpAndDeptByStepTwo" resultMap="getEmpAndDeptByStepTwoResultMap">
select * from t_dept where did = #{did}
</select>
测试方法
@Test
public void testGetEmpAndDeptByStepTwoAndOne(){
SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSession();
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = empMapper.getEmpAndDeptByStepOne(4);
System.out.println(emp);
sqlSession.close();
}
5. 一对多映射处理
多个员工对应一个部门:多对一
一个部门对应多个员工:一对多
Dept类
public class Dept {
private Integer did;
private String deptName;
private List<Emp> empList; // 多对一:使用集合的形式
//...构造器、get、set方法等
// 注意要重写toString方式
}
方式一:使用collection处理映射关系
DeptMapper接口
/**
* 根据did查询部门信息以及其所包含的员工信息
* @param did
* @return
*/
Dept getDeptAndEmp(@Param("did") Integer did);
DeptMapper接口对应的DeptMapper.xml配置文件
<!--Dept getDeptAndEmp(@Param("did") Integer did);-->
<!--方式一:使用功能collection方式处理多对一方式-->
<resultMap id="getDeptAndEmpResultMap" type="Dept">
<id property="did" column="did"/>
<result property="deptName" column="dept_name"/>
<!--
collection:处理一对多的映射关系
ofType:表示该属性所对应的集合中存储数据额类型
-->
<collection property="empList" ofType="Emp">
<id property="eid" column="eid"/>
<result property="empName" column="emp_name"/>
<result property="age" column="age"/>
<result property="sex" column="sex"/>
<result property="email" column="email"/>
</collection>
</resultMap>
<select id="getDeptAndEmp" resultMap="getDeptAndEmpResultMap">
select * from t_dept left join t_emp on t_dept.did = t_emp.did where t_dept.did = #{did}
</select>
测试方法
@Test
public void testGetDeptAndEmp(){
SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSession();
DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
Dept dept = deptMapper.getDeptAndEmp(1);
System.out.println(dept);
sqlSession.close();
}
方式二:分布查询
查询部分信息
DeptMapper接口
/**
* 根据部分的did查询属于该部分的所有员工信息
* @param did
* @return
*/
Dept getDeptAndEmpOne(@Param("did") Integer did);
DeptMapper接口对应的DeptMapper.xml配置文件
<!--Dept getDeptAndEmpOne(@Param("did") Integer did);-->
<!--方式二:一对多,使用分布查询方式-->
<resultMap id="getDeptAndEmpOneResultMap" type="Dept">
<id property="did" column="did"/>
<result property="deptName" column="dept_name"/>
<collection property="empList"
select="com.atguigu.mapper.EmpMapper.getDeptAndEmpTwo"
column="did"/>
</resultMap>
<select id="getDeptAndEmpOne" resultMap="getDeptAndEmpOneResultMap">
select * from t_dept where t_dept.did = #{did}
</select>
查询员工信息
EmpMapper接口
/**
* 根据did查询员工集合
* @param did
* @return
*/
List<Emp> getDeptAndEmpTwo(@Param("did") Integer did);
EmpMapper接口对应的EmpMapper.xml配置文件
<!--List<Emp> getDeptAndEmpTwo(@Param("did") Integer did);-->
<resultMap id="getDeptAndEmpTwoResultMap" type="Emp">
<id property="eid" column="eid"/>
<result property="empName" column="emp_name"/>
<result property="age" column="age"/>
<result property="email" column="email"/>
<result property="sex" column="sex"/>
</resultMap>
<select id="getDeptAndEmpTwo" resultMap="getDeptAndEmpTwoResultMap">
select * from t_emp where t_emp.did = #{did}
</select>
测试方法
@Test
public void testGetDeptAndEmpOne(){
SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSession();
DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
Dept dept = deptMapper.getDeptAndEmpOne(1);
System.out.println(dept);
sqlSession.close();
}
6.延迟加载
- 分步查询的优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息:
- lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载
- aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载
- 此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。此时可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载,fetchType=“lazy(延迟加载)|eager(立即加载)”
<settings>
<!--开启延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
@Test
public void testGetEmpAndDeptByStepTwoAndOne(){
SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSession();
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = empMapper.getEmpAndDeptByStepOne(4);
System.out.println(emp.getEmpName());
sqlSession.close();
}
-
关闭延迟加载,两条SQL语句都运行了
-
开启延迟加载,只运行获取emp的SQL语句
@Test
public void testGetEmpAndDeptByStepTwoAndOne(){
SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSession();
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = empMapper.getEmpAndDeptByStepOne(4);
System.out.println(emp.getEmpName());
System.out.println("===============================");
System.out.println(emp.getDept());
sqlSession.close();
}
-
开启后,需要用到查询dept的时候才会调用相应的SQL语句
-
fetchType:当开启了全局的延迟加载之后,可以通过该属性手动控制延迟加载的效果,fetchType=“lazy(延迟加载)|eager(立即加载)”
<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>
<association property="dept"
select="com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
column="did"
fetchType="lazy"></association>
</resultMap>