MyBatis的resultMap标签 自定义封装返回值类型

提示:这是MyBatis的第二篇,没看第一篇可以先看第一篇:MyBatis复习笔记整理

文章目录

  • 一、resultMap标签的association
    • 1.association标签的使用
    • 2.分步查询
    • 3.分步查询(懒加载)
  • 二、resultMap的Collection定义关联集合封装
    • 1.一步查询
    • 2.分步查询(支持懒加载)
  • 三、扩展
    • 1.多个参数作为分步查询条件
    • 2.fetchType属性
  • 四、resultMap之鉴别器
    • discriminator标签鉴别器
  • 五、下集预告


一、resultMap标签的association

1.association标签的使用

association标签可以指定联合封装的JavaBean对象,
property指定封装到哪个属性,
javaType指定这个属性的对象类型(全类名)

先配置resultMap标签,dept属性使用association标签指定:

<resultMap type="com.atguigu.bean.Employee" id="MyEmpWithDept2">
		<id column="id" property="id"/>
		<result column="last_name" property="lastName"/>
		<result column="gender" property="gender"/>
		<result column="email" property="email"/>
		<association property="dept" javaType="com.atguigu.bean.Department">



			<id column="dept_id" property="id"/>
			<result column="dept_name" property="deptName"/>
		association>
	resultMap>

再写select标签:

<select id="selectWithDeptById2" resultMap="MyEmpWithDept2">

		select a.*,b.dept_name
		from tbl_employee a
		left join tbl_dept b
		on a.dept_id = b.id
		where a.id = #{id}

	select>

这个association标签感觉跟之前用的#{dept.deptName}区别不是很大,甚至比之前要麻烦。

2.分步查询

先查询员工信息,然后用员工信息里的部门号再查询一次部门表。

先把DepartmentMapper接口和xml写好:

public interface DepartmentMapper {

	public Department selectDeptById(Integer id);
}


<mapper namespace="com.atguigu.dao.DepartmentMapper">

	<select id="selectDeptById" resultType="com.atguigu.bean.Department">
		select * from tbl_dept
		where id = #{id}
	select>
	
mapper>

EmployeeMapper接口中新增分步查询的方法selectEmpWithDeptByStep

public interface EmployeeMapperPlus {

	public Employee selectById(Integer id);
	
	public Employee selectWithDeptById(Integer id);
	
	public Employee selectWithDeptById2(Integer id);
	
	public Employee selectEmpWithDeptByStep(Integer id);
}

再配置EmployeeMapper.xmlresultMap标签,

  • dept属性使用association标签指定,
  • association的分步查询用select属性指定要调用的接口全类名.方法名
  • 方法的参数用column标签指定,使用第一步结果中的哪一列作为第二步的参数
<resultMap type="com.atguigu.bean.Employee" id="MyEmpWithDeptByStep">

		<id column="id" property="id"/>
		<result column="last_name" property="lastName"/>
		<result column="gender" property="gender"/>
		<result column="email" property="email"/>
		<association property="dept"
		 select="com.atguigu.dao.DepartmentMapper.selectDeptById"
		 column="dept_id">



			<id column="dept_id" property="id"/>
			<result column="dept_name" property="deptName"/>
		association>
	resultMap>

写Java测试代码:

	@Test
	public void test7() {
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		SqlSession openSession = sqlSessionFactory.openSession();
		try {
			EmployeeMapperPlus mapper = openSession.getMapper(EmployeeMapperPlus.class);
			Employee employee = mapper.selectEmpWithDeptByStep(7);
			System.out.println(employee);
		} finally {
			openSession.close();
		}
	}

查询结果 成功封装了dept属性:

Employee [id=7, lastName=李思, [email protected], gender=0, dept=Department [id=2, deptName=市场部]]

3.分步查询(懒加载)

懒加载:即按需加载,要用的时候才会加载。

官方文档说明:

lazyLoadingEnabled :延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType属性来覆盖该项的开关状态。

aggressiveLazyLoading :开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 否则,每个延迟加载属性会按需加载(参考 lazyLoadTriggerMethods)。

配置MyBatis配置文件:

<settings>

        <setting name="lazyLoadingEnabled" value="true"/>

        <setting name="aggressiveLazyLoading" value="false "/>
    settings>

Java测试代码 先打印员工姓名,然后再打印员工部门:

@Test
	public void test7() {
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		SqlSession openSession = sqlSessionFactory.openSession();
		try {
			EmployeeMapperPlus mapper = openSession.getMapper(EmployeeMapperPlus.class);
			Employee employee = mapper.selectEmpWithDeptByStep(7);
			System.out.println(employee.getLastName());
			System.out.println(employee.getDept());
		} finally {
			openSession.close();
		}
	}

运行结果 分为2次查询的SQL语句:

2021-07-04 14:08:54,156 [main] DEBUG [com.atguigu.dao.EmployeeMapperPlus.selectEmpWithDeptByStep] - ==> Preparing: select * from tbl_employee where id = ?
2021-07-04 14:08:54,457 [main] DEBUG [com.atguigu.dao.EmployeeMapperPlus.selectEmpWithDeptByStep] - <== Total: 1
李思
2021-07-04 14:08:54,459 [main] DEBUG [com.atguigu.dao.DepartmentMapper.selectDeptById] - ==> Preparing: select * from tbl_dept where id = ?
2021-07-04 14:08:54,462 [main] DEBUG [com.atguigu.dao.DepartmentMapper.selectDeptById] - <= Total: 1
Department [id=2, deptName=市场部]

当只查询姓名时,则不会执行第二步,也就是不会发送查询部门的SQL语句。
当要查询部门相关的信息时,才会发送查询部门的SQL语句。

二、resultMap的Collection定义关联集合封装

1.一步查询

要查询信息和部门下的所有员工信息,先在部门类中增加员工列表属性。

public class Department {

	private Integer id;
	private String deptName;
//	部门下的所有员工列表
	private List<Employee> emps;
}

DepartmentMapper接口中增加查询部门信息携带员工列表的方法:

public interface DepartmentMapper {

	public Department selectDeptById(Integer id);
	
	public Department selectDeptWithEmps(Integer id);
}

配置DepartmentMapper.xml中的resultMap:

  • collection标签指定将对象封装到集合
  • ofType属性指定将数据封装为什么类型
  • property指定要封装到类的哪个属性中
	<resultMap type="com.atguigu.bean.Department" id="deptWithEmps">
		<id column="id" property="id"/>
		<result column="dept_name" property="deptName"/>
		<collection property="emps" ofType="com.atguigu.bean.Employee">



			<id column="emp_id" property="id"/>
			<result column="last_name" property="lastName"/>
			<result column="gender" property="gender"/>
			<result column="email" property="email"/>
		collection>
	resultMap>

配置select标签,部门表左连接员工信息表,一对多:

	<select id="selectDeptWithEmps" resultMap="deptWithEmps">
		select a.*,b.id as emp_id,b.last_name,b.gender,b.email
		from tbl_dept a
		left join tbl_employee b
		on a.id = b.dept_id
		where a.id = #{id}
	</select>

编写Java测试代码:

@Test
	public void test8() {
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		SqlSession openSession = sqlSessionFactory.openSession();
		try {
			DepartmentMapper mapper = openSession.getMapper(DepartmentMapper.class);
			Department deptWithEmps = mapper.selectDeptWithEmps(1);
			System.out.println(deptWithEmps);
			
		} finally {
			openSession.close();
		}
	}

运行结果 成功封装了员工信息到部门里:

Department [id=1, deptName=开发部, emps=[Employee [id=1, lastName=tom, [email protected], gender=0], Employee [id=12, lastName=王五, [email protected], gender=0]]]

小结:
感觉collection标签和association标签用法区别不大:
association标签是指定单个对象的关联查询,select(去哪查)colunm(用什么参数查)属性;
collection标签是多个对象的关联查询,并将结果封装到集合中,使用ofType属性指定(把什么封装成集合)

2.分步查询(支持懒加载)

分步查询:先查询部门信息,然后通过部门信息中的部门id查找员工表中的数据。

select * from tbl_dept where id = #{id}
select * from tbl_employee where dept_id = #{id}

先在DepartmentMapper接口中新增分步查询方法:

public interface DepartmentMapper {

	public Department selectDeptById(Integer id);
	
	public Department selectDeptWithEmps(Integer id);
	
	public Department selectDeptWithEmpsByStep(Integer id);
}

EmployeeMapper接口中新增按部门编号查询方法:

//按部门编号查询员工信息
public List<Employee> getEmpByDeptId(String id);

EmployeeMapper.xml实现方法:

    <select id="getEmpByDeptId" resultType="com.atguigu.bean.Employee">
    	select * from tbl_Employee
    	where dept_id = #{dept_id}
    select>

DepartmentMapper.xmlresultMap

  • collection标签:表示将数据最终封装为集合形式
  • property属性:表示将数据封装到对象的哪一个属性中
  • select属性:去哪查
  • column属性:用什么作为参数查
	<resultMap type="com.atguigu.bean.Department" id="deptWithEmpsByStep">
		<id column="id" property="id"/>
		<result column="dept_name" property="deptName"/>
		<collection property="emps"
			select="com.atguigu.dao.EmployeeMapper.getEmpByDeptId"
			column="id">




			<id column="id" property="id"/>
			<result column="last_name" property="lastName"/>
			<result column="gender" property="gender"/>
			<result column="email" property="gender"/>
		collection>
	resultMap>

select标签,调用上面的resultMap完成查询

	<select id="selectDeptWithEmpsByStep" resultMap="deptWithEmpsByStep">
		select * from tbl_dept
		where id = #{id}
	select>

写Java测试代码:

@Test
	public void test9() {
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		SqlSession openSession = sqlSessionFactory.openSession();
		try {
			DepartmentMapper mapper = openSession.getMapper(DepartmentMapper.class);
			Department deptWithEmps = mapper.selectDeptWithEmpsByStep(1);
			System.out.println(deptWithEmps.getDeptName());
			System.out.println(deptWithEmps.getEmps());
			System.out.println(deptWithEmps);
		} finally {
			openSession.close();
		}
	}

输出结果 可以看到懒加载还是生效的 分了2次SQL语句:

2021-07-04 14:31:57,088 [main] DEBUG [com.atguigu.dao.DepartmentMapper.selectDeptWithEmpsByStep] - ==> Preparing: select * from tbl_dept where id = ?
2021-07-04 14:31:57,304 [main] DEBUG [com.atguigu.dao.DepartmentMapper.selectDeptWithEmpsByStep] - <= Total: 1
开发部
2021-07-04 14:31:57,306 [main] DEBUG [com.atguigu.dao.EmployeeMapper.getEmpByDeptId] - ==> Preparing: select * from tbl_Employee where dept_id = ?
2021-07-04 14:31:57,311 [main] DEBUG [com.atguigu.dao.EmployeeMapper.getEmpByDeptId] - <= Total: 2
[Employee [id=1, lastName=tom, [email protected], gender=0], Employee [id=12, lastName=王五, [email protected], gender=0]]

Department [id=1, deptName=开发部, emps=[Employee [id=1, lastName=tom, [email protected], gender=0], Employee [id=12, lastName=王五, [email protected], gender=0]]]

第一次打印部门名称的时候,并没有执行查询员工信息的SQL语句,当下面打印员工信息的时候,才执行查询员工信息的SQL

三、扩展

1.多个参数作为分步查询条件

当分步查询条件需要多个参数时,可以使用map键值对的形式,将值传递给colunm属性。
例如:

<collect colunm ="{key1=colunm1,key2=colunm2}">

2.fetchType属性

fetchType属性可局部控制该查询是否使用懒加载,默认值为lazy。
fetchType=“lazy”:表示使用延迟加载;

  • lazy : 延迟加载
  • eager:立即加载

例如:

<collect fetchType="eager">

四、resultMap之鉴别器

discriminator标签鉴别器

鉴别器:MyBatis中resultMap标签可以使用discriminator鉴别器子标签,对某列的值进行判断,然后根据判断的结果,改变其封装行为。

老板提的离谱需求:
如果员工性别=0,则查询对应的部门信息。
如果员工性别=1,则不用查询部门信息,但是需要把eamil邮箱改成last_name姓名。

这需求一看就很离谱,但没办法,他给的太多了。开干。
老规矩还是先在接口中新增方法:

public interface EmployeeMapperPlus {

	public Employee selectById(Integer id);
	
	public Employee selectWithDeptById(Integer id);
	
	public Employee selectWithDeptById2(Integer id);
	
	public Employee selectEmpWithDeptByStep(Integer id);
	//按照员工性别判断查询
	public Employee selectEmpConditionByGender(Integer id);
}

resultMap

<resultMap type="com.atguigu.bean.Employee" id="EmpConditionByGender">
		<id column="id" property="id"/>
		<result column="last_name" property="lastName"/>
		<result column="gender" property="gender"/>
		<result column="email" property="email"/>

		<discriminator javaType="string" column="gender">



			<case value="0" resultType="com.atguigu.bean.Employee">


				<association property="dept" 
					select="com.atguigu.dao.DepartmentMapper.selectDeptById"
					column="dept_id">
				association>
			case>
			<case value="1" resultType="com.atguigu.bean.Employee">


				<result column="last_name" property="email"/>
			case>
		discriminator>
	resultMap>

select标签:

<select id="selectEmpConditionByGender" resultMap="EmpConditionByGender">
		select * from tbl_employee
		where id = #{id}
	select>

写Java开查,先查一个性别=0的:

@Test
	public void test10() {
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		SqlSession openSession = sqlSessionFactory.openSession();
		try {
			EmployeeMapperPlus mapper = openSession.getMapper(EmployeeMapperPlus.class);
			Employee empConditionByGender = mapper.selectEmpConditionByGender(7);
			System.out.println(empConditionByGender);
			System.out.println(empConditionByGender.getDept());
		} finally {
			openSession.close();
		}
	}

输出结果:

2021-07-04 15:53:33,172 [main] DEBUG [com.atguigu.dao.EmployeeMapperPlus.selectEmpConditionByGender] - ==> Preparing: select * from tbl_employee where id = ?
2021-07-04 15:53:33,322 [main] DEBUG [com.atguigu.dao.EmployeeMapperPlus.selectEmpConditionByGender] - <= Total: 1
2021-07-04 15:53:33,323 [main] DEBUG [com.atguigu.dao.DepartmentMapper.selectDeptById] - ==> Preparing: select * from tbl_dept where id = ?
2021-07-04 15:53:33,324 [main] DEBUG [com.atguigu.dao.DepartmentMapper.selectDeptById] - <= Total: 1
Employee [id=7, lastName=李思, [email protected], gender=0]
Department [id=2, deptName=市场部]

正常查出了部门信息
再查一个性别=1的:
输出结果:

2021-07-04 15:58:44,942 [main] DEBUG [com.atguigu.dao.EmployeeMapperPlus.selectEmpConditionByGender] - => Preparing: select * from tbl_employee where id = ?
2021-07-04 15:58:44,990 [main] DEBUG [com.atguigu.dao.EmployeeMapperPlus.selectEmpConditionByGender] - => Parameters: 1(Integer)
2021-07-04 15:58:45,014 [main] DEBUG [com.atguigu.dao.EmployeeMapperPlus.selectEmpConditionByGender] - <= Total: 1
Employee [id=1, lastName=tom, email=tom, gender=1]
null

正常没有显示部门信息,
邮箱也改为了姓名,顺利完成
哎 真香

五、下集预告

resultMap就到这里了
再写就要提桶跑路了
下一篇:动态SQL

你可能感兴趣的:(java面试,基础复习,mysql,数据库,mybatis)