前言
从前我们只进行单表的sql操作,但是如果涉及多张表的操作,原先的映射关系就不太适用了,因此这里将会介绍Mybatis的高级结果映射技巧
准备工作
准备两张数据库表,一个员工表,一个部门表(我们使用oracle的数据表结构在mysql中实现,实现mysql的相关操作)
本文示例程序的数据模型来自oracle数据库scott示范账户的部门信息表(dept)和员工信息表(emp)。表结构如下:
departments:
employees:
需求分析:
- 如果查询结果需要返回多张表的数据,则需要配置高级结果映射,将多个类型和多张表进行映射。
- 例如如下sql语句,你无法通过简单的设置别名来完成将部门表的部门名称列dname映射到Emp类的dept属性的dname属性:
select e.employee_id,e.first_name,e.salary,d.department_id,d.department_name as departments.department_name
from employees e inner join departments d
on e.department_id = d.department_id
别名是不能带“.”符号的
注意:这里演示的是员工表到部门表的映射(这是一种多对一的映射关系):
需要在多的一方创建一的一方的对象
高级结果映射
准备工作
参照我的博客:MyBatis入门到进阶-解锁高效数据库操作技巧 ,在它的基础上创建实体类、Dao和mapper以及测试类
Departments:
我仅将需要用到的字段封装成属性,配置映射关系时也仅配置我们存在的属性对应的字段,此时sql即使查询的是所有字段,因为我们没有映射,也没有对应的属性,相当于没有查询该字段
package entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Departments implements Serializable {
private Integer department_id;
private String department_name;
}
Employees:
package entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Employees implements Serializable {
private Integer employees_id;
private String first_name;
private Double salary;
private Departments dept;
}
在多的一方(Employees)设置一的一方(Departments)的对象
EmpDao:
package dao;
import entity.Employees;
import java.util.List;
public interface EmpDao {
List<Employees> getEmpBySalAndDept(Employees emp);
}
EmpMapper:
<?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为映射的根节点,用来管理DAO接口
namespace指定DAO接口的完整类名,表示mapper配置文件管理哪个DAO接口(包.接口名)
mybatis会依据这个接口动态创建一个实现类去实现这个接口,而这个实现类是一个Mapper对象
-->
<mapper namespace="dao.EmpDao">
<resultMap id="empDept" type="entity.Employees">
<id property="employees_id" column="employees_id"/>
<result property="first_name" column="first_name"/>
<result property="salary" column="salary"/>
<association property="dept" column="department_id" javaType="entity.Departments">
<id property="department_id" column="department_id"/>
<result property="department_name" column="department_name"/>
</association>
</resultMap>
<select id="getEmpBySalAndDept" parameterType="entity.Employees" resultMap="empDept">
select * from employees e
inner join
departments d on e.department_id = d.department_id
<where>
<if test="salary>0">
e.salary > #{salary}
</if>
<if test="dept !=null and dept.department_id>0">
and e.department_id = #{dept.department_id}
</if>
</where>
</select>
</mapper>
详细分析:
- resultMap标签:配置属性和字段的映射关关系
- id属性:定义resultMap的名字;type属性:定义resultMap的类型
- id标签:配置属性和主键字段的映射关系
- property属性:属性名
- column属性:字段名
- result标签:配置我们需要查询的字段的,属性和字段的映射关系
association标签:配置高级结果映射(多对一),将部门表的部门名称列department_name映射到Emp类的dept属性的department_name属性
property属性:代表一的一方的对象名
column属性:代表外键
javaType属性:代表一的一方的类型
id标签:配置属性和主键字段的映射关系
result标签:配置我们需要查询的字段的,属性和字段的映射关系
在select标签中使用resultMap属性,resultMap的属性值为resultMap标签的id属性值
- where标签:用来包裹动态sql
- if标签:进行逻辑判断,test属性的表达式值为true拼接sql
员工到部门的关联关系映射配置,查询结果中的部门数据将会封装到Dept对象中,作为Emp对象的dept属性值和Emp对象一并返回
将resultType改成resultMap,并指定为id为empDept的映射配置
如果查询条件有多个,并且是可任意选择的,则需要采用动态条件查询技巧,使用where标签和if标签,注意if标签中的test属性值可以直接使用对象的属性来进行条件判断,不能加#{}
EmpTest:
import dao.EmpDao;
import dao.UserDao;
import entity.Departments;
import entity.Employees;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import util.SqlSessionFactoryUtil;
import java.util.List;
public class EmpTest {
SqlSession session= SqlSessionFactoryUtil.getSessionSql();
EmpDao empDao=session.getMapper(EmpDao.class);
@Test
public void testEmp() {
Employees emp = new Employees();
emp.setSalary(3000.0);
Departments dept = new Departments();
dept.setDepartment_id(50);
emp.setDept(dept);
List<Employees> list = empDao.getEmpBySalAndDept(emp);
for (Employees e : list) {
System.out.println(e.getFirst_name() + "," + e.getSalary() + ","
+ e.getDept().getDepartment_name());
}
}
}
总结
这里演示的是mybtais的高级结果映射(多对一的表映射)。目的是快速理解mybatis中实现多表查询的方式(多对一的表查询)。