首页 > 技术文章 > MyBatis的对象关系映射---多对一关系★★★★★

abcdjava 2019-07-15 21:52 原文

在实际开发中,一个业务可能涉及到多个数据表的查询,那么多表查询就涉及连接查询(等值连接), 等值连接 表与表之间有一个外键关键,但是程序中最终获取的表封装的对象, 对象与对象之间是没有外键关系的,对象和对象之间只有依赖关系;

 对象之间关系主要是四种:

一对一 关系
一个人对应身份证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&amp;characterEncoding=utf-8&amp;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=研发部]]

 

推荐阅读