自定义映射resultMap
resultType
:默认使用的映射关系。表的字段和实体类对象的名称相同才会自动建立映射关系,然后把查询出来的字段名与对应的属性赋值
resultMap
:专门解决某一个类型与查询结果的映射关系
但是表的字段有多个单词时,是用_
分隔,而Java属性是用驼峰命名,这就导致了字段和属性名称不一致的问题
实现准备
部门表
CREATE TABLE t_dept(
did INT PRIMARY KEY auto_increment,
dept_name varchar(20)
)
INSERT INTO t_dept VALUE(null,'A');
INSERT INTO t_dept VALUE(null,'B');
INSERT INTO t_dept VALUE(null,'C');
员工表
员工表中包含了部门表的id
CREATE TABLE t_emp(
eid INT PRIMARY KEY auto_increment,
emp_name varchar(20),
age INT,
sex char,
email varchar(20),
did INT
)
INSERT INTO t_emp values(null,'张三',23,'男','123@qq.com',1);
INSERT INTO t_emp values(null,'李四',21,'女','123@qq.com',2);
INSERT INTO t_emp values(null,'王五',19,'男','123@qq.com',3);
INSERT INTO t_emp values(null,'赵六',45,'男','123@qq.com',1);
INSERT INTO t_emp values(null,'田七',33,'女','123@qq.com',2);
部门表对应的实体类
员工表对应的实体类
1、resultMap处理字段和属性的映射关系
<!--
resultMap: 设置自定义映射
属性:
id:表示自定义映射的唯一标识
type:查询的数据要映射的实体类的类型
子标签:
id:设置主键的映射关系
result:设置普通字段的映射关系
association:设置多对一的映射关系
collection:设置一对多的映射关系
属性:
property:设置映射关系中的属性名,必须是type属性所设置的实体类类型中的属性名
column:设置映射关系中的字段名,必须是sql语句查询出的字段名
-->
<!--通过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>
<!--List<Emp> getAllEmp();-->
<!--resultMap="自定义映射id"-->
<select id="getAllEmp" resultMap="empResultMap">
select * from t_emp;
</select>
若字段名和实体类中的属性名不一致,但是字段名符合数据库的规则(使用_),实体类中的属性
名符合Java的规则(使用驼峰)
此时也可通过以下两种方式处理字段名和实体类中的属性的映射关系
a>可以通过为字段起别名的方式,保证和实体类中的属性名保持一致
b>可以在MyBatis的核心配置文件中设置一个全局配置信息mapUnderscoreToCamelCase,可
以在查询表中数据时,自动将_类型的字段名转换为驼峰
例如:字段名user_name,设置了mapUnderscoreToCamelCase,此时字段名就会转换为
userName
a> 起别名的方式处理字段和属性的映射关系
/**
* 查询所有员工信息
*/
List<Emp> getAllEmp();
<!--List<Emp> getAllEmp();-->
<select id="getAllEmp" resultType="Emp">
select eid,emp_name empName,age,sex,email from t_emp
</select>
b> 通过全局配置mapUnderscoreToCamelCasep处理字段和属性的映射关系
mybatis-config
<!--设置MyBatis的全局配置-->
<settings>
<!--将_自动转换成驼峰,emp_name:empName-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!--List<Emp> getAllEmp();-->
<select id="getAllEmp" resultType="Emp">
select * from t_emp
</select>
2、多对一映射处理
实体类与实体类之间的映射关系:
多对一
在"多"
实体类创建一个"一"
的属性
一对多
在"一"
实体类创建一个"多"
的集合属性
1、级联赋值
/**
* 根据id查询用户信息
*/
Emp getEmpAndDept(@Param("did") Integer did);
<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("did") Integer did);-->
<select id="getEmpAndDept" resultMap="empAndDeptResultMapOne">
select * from t_emp left join t_dept on t_emp.did = t_dept.did where eid = #{did}
</select>
2、使用association处理映射关系
- association:处理多对一的映射关系
- property:需要处理多对的映射关系的属性名
- javaType:该属性的类型
<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:需要处理多对的映射关系的属性名
javaType:该属性的类型
* 会在底层通过反射创建一个Dept对象,并将column对应的字段赋值给property对应的属性
最后将这个对象赋值给在<association>标签中property对应的属性
-->
<association property="dept" javaType="Dept">
<id property="did" column="did"></id>
<result property="deptName" column="dept_name"></result>
</association>
</resultMap>
<!-- Emp getEmpAndDept(@Param("did") Integer did);-->
<select id="getEmpAndDept" resultMap="empAndDeptResultMapTwo">
select * from t_emp left join t_dept on t_emp.did = t_dept.did where eid = #{did}
</select>
3、分步查询
1. 查询员工信息
EmpMapper接口方法
/**
* 通过分步查询查询员工以及员工所对应的部门信息
* 分步查询第一步:查询员工信息
*/
Emp getEmpAndDeptByStepOne(@Param("eid") Integer eid);
EmpMapper.xml
- select:设置分布查询的sql的唯一标识(namespace.SQLId或mapper接口的全类名.方法名)
- column:设置分步查询的条件,该属性对应的值为
当前sql语句
查询出的字段名,并作为参数传递给select属性对应sql语句
<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:设置分布查询的条件,也就传递给select属性对应sql语句的参数
* select属性对应的sql语句执行完后,会将返回值赋值给property对应的属性
-->
<association property="dept"
select="com.study.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
column="did">
</association>
</resultMap>
<!--Emp getEmpAndDeptByStepOne(@Param("eid") Integer eid);-->
<select id="getEmpAndDeptByStepOne" resultMap="empAndDeptByStepResultMap">
select * from t_emp where eid = #{eid}
</select>
2. 查询部门信息
DeptMapper接口方法
/**
* 通过分步查询查询员工以及员工所对应的部门信息
* 分步查询第二步:通过did查询员工所对应的部门
* 返回值为第一条语句设置的property属性对应的类型
* 当此条sql执行完后,会将返回值返回
*/
Dept getEmpAndDeptByStepTwo(@Param("did") Integer did);
DeptMapper.xml
<resultMap id="deptResultMap" type="Dept">
<id property="did" column="did"></id>
<result property="deptName" column="dept_name"></result>
</resultMap>
<!--Dept getEmpAndDeptByStepTwo(@Param("did") Integer did);-->
<select id="getEmpAndDeptByStepTwo" resultMap="deptResultMap">
select * from t_dept where did = #{did}
</select>
看结果,是执行了两次sql语句
延迟加载
延迟加载:在关联查询时,利用延迟加载,先加载主信息。使用关联信息时再去加载关联信息。
mybatis-config
<!--设置MyBatis的全局配置-->
<settings>
<!--开启延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
测试一:只获取emp表中的信息
@Test
public void testGetEmpAndDeptByStepOne() {
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = mapper.getEmpAndDeptByStepOne(4);
System.out.println(emp.getEmpName());
}
可以发现:如果只获取主信息,那么只会执行第一条sql语句
测试二:只获取emp表中dept表的信息
@Test
public void testGetEmpAndDeptByStepOne() {
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = mapper.getEmpAndDeptByStepOne(4);
System.out.println(emp.getDept());
}
可以发现:只有执行了第二条sql语句,才能获取到dept的信息,那么就会执行两条sql语句
测试三:获取emp表中的信息以及emp表中dept表的信息
@Test
public void testGetEmpAndDeptByStepOne() {
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = mapper.getEmpAndDeptByStepOne(4);
System.out.println(emp.getEmpName());
System.out.println("++++++++++++++++++++++++");
System.out.println(emp.getDept());
}
可以发现:sql语句是分开执行的,获取员工,就只会执行获取员工的sql;获取部门,执行获取部门的sql
分布查询设置为立即加载
当设置了延迟加载,那么所有的分布查询都会有延迟加载的功能,那么有部分分布查询是不需要延迟的加载,那么就会设置为立即加载
<!--
fetchType:当开启了全局的延迟加载之后,可通过此属性手动控制延迟加载的效果
fetchType="lazy /eager": Lazy表示延迟加载,eager表示立即加载
-->
<association property="dept"
select="com.study.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
column="did"
fetchType="eager">
</association>
分步查询的优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息:
lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象(第二步、第三步…)都会延迟加载
aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个
属性会按需加载
此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。
此时可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载,fetchType=“lazy(延迟加载)|eager(立即加载)”
3、一对多映射处理
一对多的关系:
一对多
在"一"
实体类创建一个"多"
的集合属性
1、collection
/**
* 获取部门以及部门中所有的员工信息
*/
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:用来处理一对多的映射关系-->
<!--ofType:表示该属性对应的集合中存储的数据的类型-->
<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") Integer did);-->
<select id="getDeptAndEmp" resultMap="deptAndEmpResultMap">
select * from t_emp left join t_dept on t_emp.did = t_dept.did where t_dept.did = #{did}
</select>
2、分步查询
1、查询部门信息
DeptMapper的接口方法
/**
* 通过分步查询查询部门以及部门中所有的员工信息
* 分步查询第一步:查询部门信息
*/
Dept getDeptAndEmpByStepOne(@Param("did") Integer did);
DeptMapper.xml
<resultMap id="DeptAndEmpByStepOneResultMap" type="Dept">
<id property="did" column="did"></id>
<result property="deptName" column="dept_name"></result>
<collection property="emps"
select="com.study.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo"
column="did">
</collection>
</resultMap>
<!--Dept getDeptAndEmpByStepOne(@Param("did") Integer did);-->
<select id="getDeptAndEmpByStepOne" resultMap="DeptAndEmpByStepOneResultMap">
select * from t_dept where did = #{did}
</select>
2、查询员工信息
EmpMapper的接口方法
/**
* 通过分步查询查询部门以及部门中所有的员工信息
* 分步查询第一步:查询部门信息
*/
List<Emp> getDeptAndEmpByStepTwo(@Param("did") Integer did);
EmpMapper.xml
<resultMap id="deptAndEmpByStepTwo" 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> getDeptAndEmpByStepTwo(@Param("did") Integer did);-->
<select id="getDeptAndEmpByStepTwo" resultMap="deptAndEmpByStepTwo">
select * from t_emp where did = #{did}
</select>
同样可以使用延迟加载