MyBatis的对象关系映射---多对一关系★★★★★
在实际开发中,一个业务可能涉及到多个数据表的查询,那么多表查询就涉及连接查询(等值连接), 等值连接 表与表之间有一个外键关键,但是程序中最终获取的表封装的对象, 对象与对象之间是没有外键关系的,对象和对象之间只有依赖关系;
对象之间关系主要是四种:
一对一 关系
一个人对应身份证id,一个QQ号对应一个QQ空间
一对多 关系
一个部门对应多个员工
多对一 关系
多个员工对应一个部门
多对多 关系
多个学生对应多个老师,多个学生对应多个课程
什么关系应该从哪个对象作为中心点来看
一对多, 以one方作为中心点
MyBatis框架支持多表查询封装对象之间关系
<collection> 一对多查询 <association>多对一和一对一查询
mapper表:
1 package top.abcdit.mybatis.mapper; 2 3 import top.abcdit.mybatis.pojo.Employee; 4 5 public interface Many2OneMapper { 6 7 /** 8 * 查询指定id员工的所有信息(包括部门信息) 9 * @param id 员工id 10 * @return 员工对象 11 */ 12 Employee selectByPrimaryKey(Integer id); 13 14 }
Many2OneMapper.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"> <!-- 映射标签,内部就编写具体的映射sql语句 namespace :命名空间,值 必须是 对应接口的全限定名 = 包名 +简单类名 top.abcdit.mybatis.mapper.Many2OneMapper --> <mapper namespace="top.abcdit.mybatis.mapper.Many2OneMapper"> <select id="selectByPrimaryKey" resultType="top.abcdit.mybatis.pojo.Employee" parameterType="int"> select * from employee where id = #{id} </select> </mapper>
mybatis-config.xml文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <!-- mybatis配置标签 内部就是mybatis具体配置 --> <configuration> <!-- mybatis的配置环境 default:默认使用环境,值就是下面的环境id --> <settings> <!-- 开启二级缓存 --> <setting name="cacheEnabled" value="true"/> </settings> <environments default="mysql"> <!-- 具体某一个环境 --> <environment id="mysql"> <!-- MyBatis操作需要事务管理,默认使用JDBC JDBC:mybatis的别名 --> <transactionManager type="JDBC"/> <!--配置mybatis的数据源(连接池) POOLED(别名) :mybatis内置的一个连接池 后期和spring集成使用,druid阿里巴巴连接池 --> <dataSource type="POOLED"> <!-- 数据库驱动 --> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <!-- url地址 --> <property name="url" value="jdbc:mysql://localhost:3306/gzmybatis1?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT"/> <!-- 数据库的账号 --> <property name="username" value="root"/> <!-- 数据库的密码 --> <property name="password" value="myroot"/> </dataSource> </environment> </environments> <!-- 配置映射文件 --> <mappers> <!-- 读取单个映射文件 --> <mapper resource="top/abcdit/mybatis/mapper/Many2OneMapper.xml"/> </mappers> </configuration>
员工和部门表:
1 package top.abcdit.mybatis.pojo; 2 3 public class Department { 4 private Integer id; 5 private String name; 6 public Integer getId() { 7 return id; 8 } 9 public void setId(Integer id) { 10 this.id = id; 11 } 12 public String getName() { 13 return name; 14 } 15 public void setName(String name) { 16 this.name = name; 17 } 18 public Department(Integer id, String name) { 19 super(); 20 this.id = id; 21 this.name = name; 22 } 23 public Department() { 24 super(); 25 // TODO Auto-generated constructor stub 26 } 27 @Override 28 public String toString() { 29 return "Department [id=" + id + ", name=" + name + "]"; 30 } 31 32 }
1 package top.abcdit.mybatis.pojo; 2 3 public class Employee { 4 5 private Integer id; 6 private String name; 7 //以员工为中心,多个与员工对应一个部门:多对一关系 8 private Department dept; 9 public Integer getId() { 10 return id; 11 } 12 public void setId(Integer id) { 13 this.id = id; 14 } 15 public String getName() { 16 return name; 17 } 18 public void setName(String name) { 19 this.name = name; 20 } 21 public Department getDept() { 22 return dept; 23 } 24 public void setDept(Department dept) { 25 this.dept = dept; 26 } 27 public Employee(Integer id, String name, Department dept) { 28 super(); 29 this.id = id; 30 this.name = name; 31 this.dept = dept; 32 } 33 public Employee() { 34 super(); 35 } 36 @Override 37 public String toString() { 38 return "Employee [id=" + id + ", name=" + name + ", dept=" + dept + "]"; 39 } 40 41 42 43 }
测试表:
1 package top.abcdit.mybatis.test; 2 3 import static org.junit.Assert.*; 4 5 import org.apache.ibatis.session.SqlSession; 6 import org.junit.Test; 7 import top.abcdit.mybatis.mapper.Many2OneMapper; 8 import top.abcdit.mybatis.pojo.Employee; 9 import top.abcdit.mybatis.util.MyBatisUtil; 10 11 public class Many2OneMapperTest { 12 13 @Test 14 public void testselectByPrimaryKey() { 15 16 SqlSession session = MyBatisUtil.openSession(); 17 18 Many2OneMapper mapper = session.getMapper(Many2OneMapper.class); 19 20 Employee emp = mapper.selectByPrimaryKey(2); 21 System.out.println(emp); 22 } 23 24 25 }
输出结果:
DEBUG [main] - ==> Preparing: select * from employee where id = ? DEBUG [main] - ==> Parameters: 2(Integer) TRACE [main] - <== Columns: id, name, dept_id TRACE [main] - <== Row: 2, 虚竹, 2 DEBUG [main] - <== Total: 1 Employee [id=2, name=虚竹, dept=null]
可以看到,采用自动映射,只得到部门编号,无法获取部门名称;
所以采用手动映射:
把Many2OneMapper.xml:配置文件修改为:
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 6 <!-- 映射标签,内部就编写具体的映射sql语句 7 namespace :命名空间,值 必须是 对应接口的全限定名 = 包名 +简单类名 8 top.abcdit.mybatis.mapper.Many2OneMapper 9 --> 10 <mapper namespace="top.abcdit.mybatis.mapper.Many2OneMapper"> 11 12 <select id="selectByPrimaryKey" resultMap="emp_map" parameterType="int"> 13 select * from employee where id = #{id} 14 </select> 15 16 <!-- 手动映射 --> 17 <resultMap type="top.abcdit.mybatis.pojo.Employee" id="emp_map"> 18 <id column="id" property="id"/> 19 <result column="name" property="name"/> 20 21 <!-- 22 问题: private Department dept; 部门对象如何映射? 23 24 解决方案:使用 联合查询标签 25 <association property="" column="" select=""/> 26 property :需要映射的pojo对象的属性此时就是 dept 27 column :已知对应dept对象的外键列 28 select :需要去查询的功能id --> 29 30 <association property="dept" column="dept_id" select="findByDeptId"/> 31 </resultMap> 32 33 <!-- 联合查询的功能 --> 34 <!-- 根据部门的id查询出对应的部门对象--> 35 36 <select id="findByDeptId" parameterType="int" resultType="top.abcdit.mybatis.pojo.Department"> 37 select * from department where id = #{dept_id} 38 </select> 39 40 </mapper>
测试结果:
DEBUG [main] - ==> Preparing: select * from employee where id = ? DEBUG [main] - ==> Parameters: 2(Integer) TRACE [main] - <== Columns: id, name, dept_id TRACE [main] - <== Row: 2, 虚竹, 2 DEBUG [main] - ====> Preparing: select * from department where id = ? DEBUG [main] - ====> Parameters: 2(Integer) TRACE [main] - <==== Columns: id, name TRACE [main] - <==== Row: 2, 研发部 DEBUG [main] - <==== Total: 1 DEBUG [main] - <== Total: 1 Employee [id=2, name=虚竹, dept=Department [id=2, name=研发部]]