MyBatis中在查询进行select映射的时候,返回类型可以用resultType,也可以用resultMap,resultType就是 mybatis会自己通过反射 根据字段名设置到对应的实例中的属性。
而resultMap则是对外部ResultMap的引用,resultMap就是你自定义的一个映射关系
而且resultMap可以实现一种功能
就是当你是1对多 这种多张表查询的时候 你没办法 通过表连接来实现一个集合设置到一个实例里,但是通过resultMap里可以做到 根据关联的字段 查询到一个集合 然后把集合设置到 那个对象的对应属性。
但是resultType跟resultMap不能同时存在。
案例:通过员工id 查询 员工的信息 以及 所在部门信息
-- emp员工表中存储的是 员工的信息
-- dept部门表中存储的是部门的信息
-- 而员工的id只有emp表中有,部门名字也只有dept表中有
-- 员工表和部门表中的共有属性是:部门编号,部门编号是一样的
-- 这里要同时查询两张表才能查出来
一个员工对应一个部门,一对一关系。
数据库两张表 :
employee员工表
Dept部门表
两个表的实体类
package com.mybatis.bean;
/***
* 部门实体类
*/
public class Dept {
private Integer did; //部门id
private String dname; //部门名称
//..........省略 set get 方法
}
/**
* 员工实体类
*/
public class Employee {
//实体类字段建议和数据库字段名一致
private Integer id; //员工id
private String name; //员工姓名
private String sex; //性别
private Integer money; //工资
//部门实体类 成员变量
private Dept dept;
//...........省略set get 方法
}
两个表的持久层
/**
* Employee 的持久层接口
*
*/
public interface EmployeeMapper {
//根据员工id 查询员工信息 以及 员工部门信息
public abstract Employee findEmpAndDept(Integer id);
/**
* 根据员工id 查询员工信息 以及 员工部门信息
* 利用已经有的select方法 ------->>>> 分步查询
*/
public abstract Employee findEmpStep(Integer id);
}
/**
* 操作部门的DAO接口
*/
public interface DeptMapper {
//根据部门id查询部门
public abstract Dept findDeptById(Integer id);
}
1.第一种解决方式 (使用员工id关联查询两张表格) 并使用 resultMap的级联关系封装结果集
EmployeeMapper.xml (员工表SQL映射文件配置)
<mapper namespace="com.mybatis.dao.EmployeeMapper">
<!-- 自定义实体类的封装规则 第一种方式:级联关系 -->
<resultMap id="Emp1" type="com.mybatis.bean.Employee" >
<!-- 主键封装规则-->
<id column="id" property="id" />
<!-- 普通字段封装规则 -->
<result column="name" property="name" />
<result column="sex" property="sex" />
<result column="money" property="money" />
<!-- 关联查询,级联属性封装结果集 -->
<!-- 将部门id和部门名称封装到 dept成员对象中 -->
<result column="dept_id" property="dept.did"/> <!-- property:dept.did (封装到dept成员对象 的did字段中) -->
<result column="dept_name" property="dept.dname"/>
</resultMap>
<!-- 根据员工id 查询员工信息 以及 员工部门信息 -->
<select id="findEmpAndDept" resultMap="Emp1"> <!-- resultMap引用封装规则 -->
SELECT
e.id, e.name, e.sex, e.money, d.did dept_id, d.dname dept_name
FROM
employee e,dept d
WHERE
e.id = #{id} AND e.dept_id = d.did
</select>
</mapper>
controller
SqlSession session = sqlSessionFactory.openSession();
EmployeeMapper mapper = session.getMapper(EmployeeMapper.class); //利用反射创建employee的持久层实现类
//查询id为1 的员工信息以及所在部门信息
Employee employee = mapper.findEmpAndDept(1);
System.out.println(employee.toString());
Employee [id=1, name=tom, money=1200, sex=man, dept=Dept [did=2, dname=运营部]]
2.第二种方式 (使用员工id关联查询两张表格) 并使用 resultMap封装结果集(association 属性指定联合的javabean对象)
EmployeeMapper.xml
<mapper namespace="com.mybatis.dao.EmployeeMapper">
<!-- 自定义实体类的封装策略 第二种方式:association指定联合的javabean对象 -->
<resultMap id="Emp2" type="com.mybatis.bean.Employee" >
<!-- 主键封装规则-->
<id column="id" property="id" />
<!-- 普通字段封装规则 -->
<result column="name" property="name" />
<result column="sex" property="sex" />
<result column="money" property="money" />
<!-- association 指定联合的javabean对象 (关联的对象)
属性:property :指定联合的javabean对象的属性名 (Employee中的 成员对象dept)
javaType: 指定java类型
-->
<association property="dept" javaType="com.mybatis.bean.Dept">
<!-- 定义dept对象封装规则 -->
<id column="dept_id" property="did" />
<id column="dept_name" property="dname" />
</association>
</resultMap>
<!-- 根据员工id 查询员工信息 以及 员工部门信息 -->
<select id="findEmpAndDept" resultMap="Emp2"> <!-- resultMap指定封装规则 -->
SELECT
e.id, e.name, e.sex, e.money, d.did dept_id, d.dname dept_name
FROM
employee e,dept d
WHERE
e.id = #{id} AND e.dept_id = d.did;
</select>
</mapper>
controller
String resource = "mybatis_config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
EmployeeMapper mapper = session.getMapper(EmployeeMapper.class); //利用反射创建employee的持久层实现类
//直接查询两张表,一次性查询出来
Employee employee = mapper.findEmpAndDept(1);
System.out.println(employee.toString());
Employee [id=1, name=tom, money=1200, sex=man, dept=Dept [did=2, dname=运营部]]
使用两种方式都可以
第一种方式级联关系更加简单,只能关联数据,功能比较单一
第二种方式association功能更加完善, 不仅可以关联数据、还可以进行分步查询
3.第三种方式 使用 resultMap封装结果集 并使用其子属性association分步查询
查询出员工的信息,以及部门id和部门名称
利用已经有的查询方法
1.通过员工的id查询出员工的个人信息 >>>查询员工表 Employee
2.在通过员工信息中的部门id,查询部门 >>>查询部门表 Dept
将两次查询的结果封装到一起
DeptMapper.xml 部门表的SQL映射文件
<mapper namespace="com.mybatis.dao.DeptMapper">
<!-- 该xml是 操作Dept部门表的 SQL映射文件 -->
<!-- 按照id查询部门 -->
<!-- public abstract Dept findDeptById(Integer id) -->
<select id="findDeptById" resultType="com.mybatis.bean.Dept">
SELECT * FROM dept where did = #{id}
</select>
</mapper>
EmployeeMapper.xml (员工表的SQL映射文件,实现持久层接口中的分步查询方法 findEmpStep)
<mapper namespace="com.mybatis.dao.EmployeeMapper">
<!-- 定义对象封装规则 -->
<resultMap id="EmpByStep" type="com.mybatis.bean.Employee">
<id column="id" property="id" /> <!-- 主键字段封装 -->
<!-- 普通字段封装规则 -->
<result column="name" property="name" />
<result column="sex" property="sex" />
<result column="money" property="money"/>
<!-- association 分步查询 -->
<!--
property: 指定联合的bean对象(Employee的成员对象dept)
select:指定关联的dept属性,是调用哪一个SQL映射文件中的方法查询出来的结果
索引SQL映射文件和方法 : (SQL映射文件的名称空间+调用的方法名)
column: 指定将那一列的结果集传递给这个方法 (将结果集中的dept_id字段传递给此方法)
-->
<association property="dept" select="com.mybatis.dao.DeptMapper.findDeptById" column="dept_id">
</association>
</resultMap>
<!-- 分步查询 -->
<!-- public abstract Employee findEmpStep(Integer id); -->
<select id="findEmpStep" resultMap="EmpByStep"> <!-- resultMap引用结果集封装规则 -->
select * from employee where id = #{id}
</select>
</mapper>
controller
String resource = "mybatis_config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
EmployeeMapper mapper = session.getMapper(EmployeeMapper.class); //利用反射创建employee的持久层实现类
//分步查询: 1.先查询员工信息,获取到部门id --->> 2.在调用部门持久层的findDeptById方法查询部门信息
Employee empStep = mapper.findEmpStep(1);
System.out.println(empStep.toString());