本章介绍Mybatis之表的关联查询
一对一关联
查询员工信息以及员工的部门信息
1、准备表employee员工表,department部门表
1 CREATE TABLE `employee` ( 2 `id` int(11) NOT NULL AUTO_INCREMENT, 3 `last_name` varchar(255) DEFAULT NULL, 4 `gender` char(1) DEFAULT NULL, 5 `email` varchar(255) DEFAULT NULL, 6 `dept_id` int(11) DEFAULT NULL COMMENT '部门ID', 7 PRIMARY KEY (`id`) 8 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1 CREATE TABLE `department` ( 2 `id` int(11) NOT NULL AUTO_INCREMENT, 3 `dep_name` varchar(255) DEFAULT NULL, 4 PRIMARY KEY (`id`) 5 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2、新建员工实体类(EmployeePlus.java),以及部门实体类(Department.java)
1 package com.hd.test.pojo; 2 3 public class EmployeePlus { 4 5 private Integer id; 6 private String lastName; 7 private String gender; 8 private String email; 9 10 private Department dept; 11 12 public EmployeePlus() { 13 // TODO Auto-generated constructor stub 14 } 15 16 public EmployeePlus(String lastName, String gender, String email) { 17 super(); 18 this.lastName = lastName; 19 this.gender = gender; 20 this.email = email; 21 } 22 23 24 public EmployeePlus(Integer id, String lastName, String gender, String email) { 25 super(); 26 this.id = id; 27 this.lastName = lastName; 28 this.gender = gender; 29 this.email = email; 30 } 31 32 33 public Integer getId() { 34 return id; 35 } 36 public void setId(Integer id) { 37 this.id = id; 38 } 39 public String getLastName() { 40 return lastName; 41 } 42 public void setLastName(String lastName) { 43 this.lastName = lastName; 44 } 45 public String getGender() { 46 return gender; 47 } 48 public void setGender(String gender) { 49 this.gender = gender; 50 } 51 public String getEmail() { 52 return email; 53 } 54 public void setEmail(String email) { 55 this.email = email; 56 } 57 58 public Department getDept() { 59 return dept; 60 } 61 62 63 public void setDept(Department dept) { 64 this.dept = dept; 65 } 66 67 @Override 68 public String toString() { 69 return "EmployeePlus [id=" + id + ", lastName=" + lastName + ", gender=" + gender + ", email=" + email 70 + ", dept=" + dept + "]"; 71 } 72 73 74 }
1 package com.hd.test.pojo; 2 3 public class Department { 4 5 private Integer id; 6 private String deptName; 7 8 public Integer getId() { 9 return id; 10 } 11 public void setId(Integer id) { 12 this.id = id; 13 } 14 public String getDeptName() { 15 return deptName; 16 } 17 public void setDeptName(String deptName) { 18 this.deptName = deptName; 19 } 20 21 @Override 22 public String toString() { 23 return "Department [id=" + id + ", deptName=" + deptName + "]"; 24 } 25 26 }
3、编辑sql映射文件EmployeeMapperPlus.xml,文件中有2种resultMap,都可以使用
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 3 4 <mapper namespace="com.hd.test.mapper.EmployeeMapperPlus"> 5 6 <!-- 联合查询:级联属性封装结果集 --> 7 <!-- 封装方式1:普通封装 --> 8 <resultMap type="com.hd.test.pojo.EmployeePlus" id="MyEmployeeDept"> 9 <id column="id" property="id"/> 10 <result column="last_name" property="lastName"/> 11 <result column="gender" property="gender"/> 12 <result column="did" property="dept.id"/> 13 <result column="dept_name" property="dept.deptName"/> 14 </resultMap> 15 16 <!-- 封装方式2:采用association标签的方式封装 --> 17 <resultMap type="com.hd.test.pojo.EmployeePlus" id="MyEmployeeDept2"> 18 <id column="id" property="id"/> 19 <result column="last_name" property="lastName"/> 20 <result column="gender" property="gender"/> 21 22 <association property="dept" javaType="com.hd.test.pojo.Department"> 23 <id column="did" property="id"/> 24 <result column="dept_name" property="deptName"/> 25 </association> 26 </resultMap> 27 28 <select id="getMyEmployeeDept" resultMap="MyEmployeeDept" > <!-- resultMap="MyEmployeeDept2" --> 29 SELECT 30 emp.id, 31 emp.last_name, 32 emp.gender, 33 dept.id AS did, 34 dept.dep_name AS dept_name 35 FROM 36 employee emp 37 LEFT JOIN department dept ON emp.dept_id = dept.id 38 WHERE 39 emp.id = #{id} 40 </select> 41 42 </mapper>
4、在mybatis-config.xml文件中注册EmployeeMapperPlus.xml
1 <mappers> 2 <!-- 添加sql射文件到Mybatis的全局配置文件中 --> 3 <mapper resource="mapper/EmployeeMapperPlus.xml" /> 4 </mappers>
5、编写接口(DepartmentPlusMapper.java)
1 package com.hd.test.mapper; 2 3 import com.hd.test.pojo.DepartmentPlus; 4 5 public interface DepartmentPlusMapper { 6 7 public DepartmentPlus getDeparmentAndEmp(Integer id); 8 9 }
6、测试类
1 @Test 2 public void test01() throws IOException { 3 4 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); 5 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 6 7 SqlSession session = sqlSessionFactory.openSession(); 8 9 try { 10 EmployeeMapperPlus mapper = session.getMapper(EmployeeMapperPlus.class); 11 EmployeePlus employeePlus = mapper.getMyEmployeeDept(1); 12 System.out.println(employeePlus); 13 14 } catch (Exception e) { 15 e.printStackTrace(); 16 }finally { 17 session.close(); 18 } 19 20 }
7、执行结果,可以看到员工和部门信息同时查出来了,如下:
一对一关联查询拓展
a、分步的形式查询,即先查员工信息,然后查部门执行,需要执行2次sql
1)编辑EmployeeMapperPlus.xml文件,新增内容
1 <resultMap type="com.hd.test.pojo.EmployeePlus" id="MyEmployeeByStep"> 2 <id column="id" property="id"/> 3 <result column="last_name" property="lastName"/> 4 <result column="gender" property="gender"/> 5 6 <association property="dept" select="com.hd.test.mapper.DepartmentMapper.getDeparmentById" column="dept_id"> 7 8 </association> 9 </resultMap> 10 11 <select id="getMyEmployeeByStep" resultMap="MyEmployeeByStep" > 12 SELECT id, last_name, gender, dept_id FROM employee WHERE id = #{id} 13 </select>
2)新增一个 DepartmentMapper.xml 文件,并且也在mybatis-config.xml文件中注册
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 3 4 <mapper namespace="com.hd.test.mapper.DepartmentMapper"> 5 <select id="getDeparmentById" resultType="com.hd.test.pojo.Department"> 6 select id, dep_name deptName from department where id = 7 #{id} 8 </select> 9 </mapper>
3、调用方法如下:
1 @Test 2 public void test02() throws IOException { 3 4 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); 5 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 6 7 SqlSession session = sqlSessionFactory.openSession(); 8 9 try { 10 EmployeeMapperPlus mapper = session.getMapper(EmployeeMapperPlus.class); 11 EmployeePlus employeePlus = mapper.getMyEmployeeByStep(1); 12 System.out.println(employeePlus.getLastName()); 13 System.out.println(employeePlus.getDept()); 14 } catch (Exception e) { 15 e.printStackTrace(); 16 }finally { 17 session.close(); 18 } 19 20 }
4、执行结果如下,可以从日志中看到,先执行sql查询了员工信息表的数据,然后在执行sql查询了部门表的数据,分两次查询
b、分步的形式懒加载查询,即先查员工信息,然后在需要使用部门信息的时候,在去查询部门信息
方法1:在上面分步的形式查询基础上,在mybatis-config.xml文件中设置全局变量,然后执行
1 <settings> 2 <!-- 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态。 --> 3 <setting name="lazyloadingenabled" value="true"/> 4 <!-- 当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载 --> 5 <setting name="aggressivelazyloading" value="false"/> 6 </settings>
方法2:在上面分步的形式查询基础上,在sql配置文件中,配置resultMap中association标签的 fetchType 属性,fetchType 属性有2个值:lazy(懒加载),eager(立即加载),然后执行
1 <resultMap type="com.hd.test.pojo.EmployeePlus" id="MyEmployeeByStep"> 2 <id column="id" property="id"/> 3 <result column="last_name" property="lastName"/> 4 <result column="gender" property="gender"/> 5 6 <association property="dept" select="com.hd.test.mapper.DepartmentMapper.getDeparmentById" column="dept_id" fetchType="lazy"> 7 </association> 8 </resultMap>
优先级:association标签的 fetchType 属性设置的优先级高于mybatis-config.xml文件中的e设置
一对多关联
查询部门信息,以及部门下所有员工信息
1、表结构上,2张表,员工和部门
2、新建部门实体类(DepartmentPlus.java),以及员工实体类(Employee.java)
DepartmentPlus.java
1 package com.hd.test.pojo; 2 3 import java.util.List; 4 5 public class DepartmentPlus { 6 7 private Integer id; 8 private String deptName; 9 10 private List<Employee> emps; 11 12 public Integer getId() { 13 return id; 14 } 15 public void setId(Integer id) { 16 this.id = id; 17 } 18 public String getDeptName() { 19 return deptName; 20 } 21 public void setDeptName(String deptName) { 22 this.deptName = deptName; 23 } 24 @Override 25 public String toString() { 26 return "DepartmentPlus [id=" + id + ", deptName=" + deptName + ", emps=" + emps + "]"; 27 } 28 public List<Employee> getEmps() { 29 return emps; 30 } 31 public void setEmps(List<Employee> emps) { 32 this.emps = emps; 33 } 34 35 }
Employee.java
1 package com.hd.test.pojo; 2 3 public class Employee { 4 5 private Integer id; 6 private String lastName; 7 private String gender; 8 private String email; 9 10 11 public Integer getId() { 12 return id; 13 } 14 public void setId(Integer id) { 15 this.id = id; 16 } 17 public String getLastName() { 18 return lastName; 19 } 20 public void setLastName(String lastName) { 21 this.lastName = lastName; 22 } 23 public String getGender() { 24 return gender; 25 } 26 public void setGender(String gender) { 27 this.gender = gender; 28 } 29 public String getEmail() { 30 return email; 31 } 32 public void setEmail(String email) { 33 this.email = email; 34 } 35 @Override 36 public String toString() { 37 return "Employee [id=" + id + ", lastName=" + lastName + ", gender=" + gender + ", email=" + email + "]"; 38 } 39 40 41 }
3、编辑sql映射文件DepartmentPlusMapper.xml,文件中有2种查询方式,一种一次性查处所有数据,另一种分步查询数据
<?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="com.hd.test.mapper.DepartmentPlusMapper"> <!--嵌套结果集的方式,使用collection标签定义关联的集合类型的属性封装规则 --> <resultMap type="com.hd.test.pojo.DepartmentPlus" id="DeparmentAndEmpMap"> <id column="id" property="id"/> <id column="dep_name" property="deptName"/> <!-- collection定义关联集合类型的属性的封装规则 ofType:指定集合里面元素的类型 --> <collection property="emps" ofType="com.hd.test.pojo.Employee"> <!-- 定义这个集合中元素的封装规则 --> <id column="eid" property="id"/> <result column="last_name" property="lastName"/> <result column="email" property="email"/> <result column="gender" property="gender"/> </collection> </resultMap> <select id="getDeparmentAndEmp" resultMap="DeparmentAndEmpMap"> SELECT dept.id, dept.dep_name, emp.id AS eid, emp.last_name, emp.gender FROM department dept LEFT JOIN employee emp ON dept.id = emp.dept_id WHERE dept.id = #{id} </select> <!-- 分步查询方式 --> <resultMap type="com.hd.test.pojo.DepartmentPlus" id="DeparmentAndEmpMapByStep"> <id column="id" property="id"/> <id column="dep_name" property="deptName"/> <collection property="emps" select="com.hd.test.mapper.EmployeeMapper.getEmployeeByDeptId" column="id" fetchType="eager"> </collection> </resultMap> <!-- resultMap-collection 扩展:多列的值传递过去, 将多列的值封装map传递; column="{key1=column1,key2=column2}" 如下也是可行的 <collection property="emps" select="com.hd.test.mapper.EmployeeMapper.getEmployeeByDeptId" column="{deptId=id}" fetchType="eager"> </collection> --> <select id="getDeparmentAndEmpMapByStep" resultMap="DeparmentAndEmpMapByStep"> SELECT id, dep_name FROM department WHERE id = #{id} </select> </mapper>
4、编辑EmployeeMapper.xml文件
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 3 4 <mapper namespace="com.hd.test.mapper.EmployeeMapper"> 5 <select id="getEmployeeByDeptId" resultType="com.hd.test.pojo.Employee"> 6 select id, last_name lastName, gender, email from employee where dept_id = #{deptId}
7 </select> 8 </mapper>
5、在mybatis-config.xml文件中注册DepartmentPlusMapper.xml 和 EmployeeMapper.xml文件
6、编写接口(DepartmentPlusMapper.java)
1 package com.hd.test.mapper; 2 3 import com.hd.test.pojo.DepartmentPlus; 4 5 public interface DepartmentPlusMapper { 6 7 public DepartmentPlus getDeparmentAndEmp(Integer id); 8 9 public DepartmentPlus getDeparmentAndEmpMapByStep(Integer id); 10 11 }
7、测试类
1 @Test 2 public void test03() throws IOException { 3 4 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); 5 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 6 7 SqlSession session = sqlSessionFactory.openSession(); 8 9 try { 10 DepartmentPlusMapper mapper = session.getMapper(DepartmentPlusMapper.class); 11 DepartmentPlus departmentPlus = mapper.getDeparmentAndEmp(1); 12 System.out.println(departmentPlus); 13 // System.out.println(employeePlus.getDept()); 14 } catch (Exception e) { 15 e.printStackTrace(); 16 }finally { 17 session.close(); 18 } 19 20 } 21 22 23 @Test 24 public void test04() throws IOException { 25 26 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); 27 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 28 29 SqlSession session = sqlSessionFactory.openSession(); 30 31 try { 32 DepartmentPlusMapper mapper = session.getMapper(DepartmentPlusMapper.class); 33 DepartmentPlus departmentPlus = mapper.getDeparmentAndEmpMapByStep(1); 34 System.out.println(departmentPlus.getDeptName()); 35 System.out.println(departmentPlus.getEmps()); 36 } catch (Exception e) { 37 e.printStackTrace(); 38 }finally { 39 session.close(); 40 } 41 42 }
8、执行结果,可以看到部门信息以及部门下所有员工信息同时查出来了,如下:
a、一次性查询方法:getDeparmentAndEmp(),结果:
b、分步查询方法:getDeparmentAndEmpMapByStep(),结果: