MyBatis 的对象关系映射
在实际开发中,一个业务可能涉及到多个数据表的查询,那么多表查询就涉及连接查询(等值查询),等值查询 表与表之间有一个外键关联
但是程序中最终获取的表封装的对象,对象与对象之间是没有外键关系的,对象和对象之间只有依赖关系
对象之间的关系主要是四种
一对一 关系 one2one
一个人对应身份证id,一个QQ号对应一个QQ空间
一对多 关系 one2many
一个部门对应多个员工
多对一 关系 many2one
多个员工对应一个部门
多对多 关系 many2many
多个学生对应多个老师,多个学生对应多个课程
什么关系应该从哪个对象作为中心点来看
一对多, 以one方作为中心点
MyBatis框架支持多表查询封装对象之间关系
<collection> 一对多查询
<association>多对一和一对一查询
准备多表,表之间有外键关系(员工表和部门表)
员工表
CREATE TABLE `employee` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
`dept_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
部门表
CREATE TABLE `department` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
多对一查询
Employee
package cn.xc.mybatis.pojo;
public class Employee {
private Integer id;
private String name;
/*
* 员工和部门的关系 :多对一 many2one
*
* 在员工对象中此时具体的某一个只有一个部门
*
* 依赖管理:使用部门对象
*
*/
private Department dept;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Department getDept() {
return dept;
}
public void setDept(Department dept) {
this.dept = dept;
}
public Employee(Integer id, String name, Department dept) {
super();
this.id = id;
this.name = name;
this.dept = dept;
}
public Employee() {
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", dept=" + dept + "]";
}
}
Department
package cn.xc.mybatis.pojo;
public class Department {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Department() {
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Department [id=" + id + ", name=" + name + "]";
}
public Department(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
}
Man2oneMapper.xml 映射文件
<?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 namespace="cn.xc.mybatis.mapper.Many2OneMapper">
<!-- 根据员工的id查询出员工的所有信息(包括部门) -->
<select id="selectByPrimaryKey" resultMap="emp_map">
select id,name,dept_id from employee where id = #{id}
</select>
<!-- 手动结果集映射 -->
<resultMap type="cn.xc.mybatis.pojo.Employee" id="emp_map">
<id column="id" property="id"/>
<!--
问题:private Department dept;如何映射?
无法使用 <id>和<result>,因为这两个标签都是值映射,无法映射对象
解决方案:使用标签
<association property="" column="" select=""/>
property : 需要映射的对象属性,此场景就是 private Department dept;
column :已知可以最终得到对应对象的列,此场景就是 外键 dept_id
select : 调用能够返回 dept对象对应的查询功能
规则:命名空间 +.+功能id,如果在同一个命名空间下面可以省略 命名空间
此场景就是cn.xc.mybatis.mapper.Many2OneMapper.xml.selectByDeptId
-->
<association property="dept" column="dept_id" select="selectByDeptId"/>
</resultMap>
<!-- 联合查询专用功能:根据部门的id查询出部门对象 -->
<select id="selectByDeptId" resultType="cn.xc.mybatis.pojo.Department">
select * from department where id = #{dept_id}
</select>
</mapper>
一对多查询
以部门为中心查询部门的所有信息(包括员工),一个部门对应多个员工
Pojo对象
Employee.java
package cn.xc.mybatis.pojo;
public class Employee {
private Integer id;
private String name;
/*
* 员工和部门的关系 :多对一 many2one
*
* 在员工对象中此时具体的某一个只有一个部门
*
* 依赖管理:使用部门对象
*
*/
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Employee(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
public Employee() {
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + "]";
}
}
Department.java
package cn.xc.mybatis.pojo;
import java.util.List;
public class Department {
private Integer id;
private String name;
/*
*
* 一个部门多个员工 : one2many
*
* java程序一个部门对象对应多个员工对象 使用 集合 list,set
*
*/
List<Employee> employees;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Employee> getEmployees() {
return employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
public Department() {
// TODO Auto-generated constructor stub
}
public Department(Integer id, String name, List<Employee> employees) {
super();
this.id = id;
this.name = name;
this.employees = employees;
}
@Override
public String toString() {
return "Department [id=" + id + ", name=" + name + ", employees=" + employees + "]";
}
}
N+1方式
N+1 : N 就是当前需要查询结果对应发送的SQL语句的条数
+1 关联查询数据需要额外多发一条SQL语句才能查询出对应的结果
映射代码
<?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 namespace="cn.xc.mybatis.mapper.One2ManyMapper">
<!-- 根据部门的id查询出部门的所有信息 -->
<select id="selectByPrimaryKey" resultMap="dept_id">
select * from department where id = #{id}
</select>
<!-- 手动结果集映射 -->
<resultMap type="cn.xc.mybatis.pojo.Department" id="dept_id">
<id column="id" property="id"/>
<result column="name" property="name"/>
<!--
问题: List<Employee> employees;如何映射?
无法使用 <id>和<result>,因为这两个标签都是值映射,无法映射集合
解决方案:使用标签
<collection property="" column="" select=""/>
property :需要映射的集合属性,此场景就是 employees 集合
column :映射集合数据需要的数据列,此场景就是 部门的 id
select : 调用能够返回 employees 集合 对应的查询功能
规则:命名空间 +.+功能id,如果在同一个命名空间下面可以省略 命名空间
-->
<collection property="employees" column="id" select="selectEmployeesByDeptId"/>
</resultMap>
<!-- 联合查询专用功能,在员工表中,根据 部门的id 查询所有的对应的员工,返回的是一个集合 -->
<select id="selectEmployeesByDeptId" resultType="cn.xc.mybatis.pojo.Employee">
select * from employee where dept_id = #{dept_id}
</select>
</mapper>
运行结果
等值连接查询
映射代码
<?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 namespace="cn.xc.mybatis.mapper.One2ManyMapper">
<!-- 根据部门的id查询出部门的所有信息 -->
<select id="selectByPrimaryKey" resultMap="dept_id">
select e.id e_id,e.name e_name,d.id d_id,d.name d_name
from employee e inner join department d on e.dept_id = d.id
where d.id = #{id}
</select>
<!-- 手动结果集映射 -->
<resultMap type="cn.xc.mybatis.pojo.Department" id="dept_id">
<id column="d_id" property="id"/>
<result column="d_name" property="name"/>
<!--
问题: List<Employee> employees;如何映射?
无法使用 <id>和<result>,因为这两个标签都是值映射,无法映射集合
解决方案:使用标签
<collection property="" column="" select=""/>
property :需要映射的集合属性,此场景就是 employees 集合
ofType : 映射集合的泛型的数据类型 cn.xc.mybatis.pojo.Employee
-->
<collection property="employees" ofType="cn.xc.mybatis.pojo.Employee">
<!-- 主键列映射 -->
<id property="id" column="e_id"/>
<!-- 非主键类映射 -->
<result property="name" column="e_name"/>
</collection>
</resultMap>
</mapper>