MyBatis专题(三)-MyBatis关联映射

1.关联映射(多表查询)

数据库中多表之间存在着三种关系,如图所示。
在这里插入图片描述

多对多: 程序员<------>项目     用户--------->角色

一对多:   班级------>学生       学校------>班级      帅哥----->多个女朋友     土豪---多辆豪车

一对一:   学生----->学位证      人------>DNA        公民----身份证           房子--产权证

从图可以看出,系统设计的三种实体关系分别为:多对多、一对多和一对一关系。注意:一对多关系可以看为两种: 即一对多,多对一。

现实生活中实体和实体之间的关系: 一对多 多对多 一对一

关系:是双向的!!

2.关联映射作用

在现实的项目中进行数据库建模时,我们要遵循数据库设计范式的要求,会对现实中的业务模型进行拆分,封装在不同的数据表中,表与表之间存在着一对多或是多对多的对应关系。进而,我们对数据库的增删改查操作的主体,也就从单表变成了多表。那么Mybatis中是如何实现这种多表关系的映射呢?

查询结果集ResultMap

resultMap元素是 MyBatis中最重要最强大的元素。它就是让你远离90%的需要从结果 集中取出数据的JDBC代码的那个东西,而且在一些情形下允许你做一些 JDBC 不支持的事 情。	

有朋友会问,之前的示例中我们没有用到结果集,不是也可以正确地将数据表中的数据映射到Java对象的属性中吗?是的。这正是resultMap元素设计的初衷,就是简单语句不需要明确的结果映射,而很多复杂语句确实需要描述它们的关系。

resultMap元素中,允许有以下直接子元素:

id - 作用与result相同,同时可以标识出用这个字段值可以区分其他对象实例。可以理解为数据表中的主键,可以定位数据表中唯一一笔记录
result - 将数据表中的字段注入到Java对象属性中

association - 关联,简单的讲,就是“有一个”关系,如“用户”有一个“帐号”   has a 
collection - 集合,顾名思议,就是“有很多”关系,如“客户”有很多“订单”    has many

每个元素的用法及属性我会在下面结合使用进行讲解。

3. 一对一关联(了解)

2.1. 需求

根据班级id查询班级信息(带老师的信息)
在这里插入图片描述

2.2.创建数据表

创建一张教师表和班级表,这里我们假设一个老师只负责教一个班,那么老师和班级之间的关系就是一种一对一的关系。

CREATE TABLE teacher(
    t_id INT PRIMARY KEY AUTO_INCREMENT, 
    t_name VARCHAR(20)
);
CREATE TABLE class(
    c_id INT PRIMARY KEY AUTO_INCREMENT, 
    c_name VARCHAR(20), 
    teacher_id INT
);
ALTER TABLE class ADD CONSTRAINT fk_teacher_id FOREIGN KEY (teacher_id) REFERENCES teacher(t_id);    

INSERT INTO teacher(t_name) VALUES('teacher1');
INSERT INTO teacher(t_name) VALUES('teacher2');

INSERT INTO class(c_name, teacher_id) VALUES('class_a', 1);
INSERT INTO class(c_name, teacher_id) VALUES('class_b', 2);

2.3.定义实体类

1、Teacher类,Teacher类是teacher表对应的实体类。

public class Teacher {

	// 定义实体类的属性,与teacher表中的字段对应
	private int id; // id===>t_id
	private String name; // name===>t_name

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Teacher [id=" + id + ", name=" + name + "]";
	}
}

2、Classes类,Classes类是class表对应的实体类

public class Classes {

	// 定义实体类的属性,与class表中的字段对应
	private int id; // id===>c_id
	private String name; // name===>c_name

	/**
	 * class表中有一个teacher_id字段,所以在Classes类中定义一个teacher属性,
	 * 用于维护teacher和class之间的一对一关系,通过这个teacher属性就可以知道这个班级是由哪个老师负责的
	 */
	private Teacher teacher;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Teacher getTeacher() {
		return teacher;
	}

	public void setTeacher(Teacher teacher) {
		this.teacher = teacher;
	}

	@Override
	public String toString() {
		return "Classes [id=" + id + ", name=" + name + ", teacher=" + teacher + "]";
	}
}

2.4.定义sql映射文件classMapper.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="com.mybatis.mapper.ClassMapper">

    <!-- 
        
        select * from class c, teacher t where c.teacher_id=t.t_id and c.c_id=1
    -->
    <select id="getClass1" parameterType="int" resultMap="ClassResultMap1">
        select * from class c, teacher t where c.teacher_id=t.t_id and c.c_id=#{id}
    </select>
    
    <!-- 使用resultMap映射实体类和字段之间的一一对应关系 -->
    <resultMap type="Classes" id="ClassResultMap1">
        <id property="id" column="c_id"/>
        <result property="name" column="c_name"/>
        <association property="teacher" javaType="Teacher">
            <id property="id" column="t_id"/>
            <result property="name" column="t_name"/>
        </association>
    </resultMap>
    
   
</mapper>

2.5 编写单元测试类

	@Test
	public void test1(){
		Classes c1 = mapper.getClass1(1);
		System.out.println(c1);
	}
	
	@Test
	public void test2(){
		Classes c1 = mapper.getClass2(1);
		System.out.println(c1);
	}

2.6 MyBatis一对一关联查询总结

MyBatis中使用association(有一个)标签来解决一对一的关联查询,association标签可用的属性如下:

property:对象属性的名称
javaType:对象属性的类型
column:所对应的外键字段名称
select:使用另一个查询封装的结果

4. 一对多关联(重点)

在这里插入图片描述
在这里插入图片描述

2.1.需求

根据classId查询对应的班级信息,包括学生
在这里插入图片描述

2.2.定义实体类

1、Student类

/**
 * 学生实体
 */
public class Student {

  private long sId;
  private String sName;
  private long sAge;
  private String sEmail;
  private long classId;

  //额外准备一个班级对象
  private Classes classes;  //体现一个学生在一个班级中

  public Classes getClasses() {
    return classes;
  }

  public void setClasses(Classes classes) {
    this.classes = classes;
  }

  public long getSId() {
    return sId;
  }

  public void setSId(long sId) {
    this.sId = sId;
  }


  public String getSName() {
    return sName;
  }

  public void setSName(String sName) {
    this.sName = sName;
  }


  public long getSAge() {
    return sAge;
  }

  public void setSAge(long sAge) {
    this.sAge = sAge;
  }


  public String getSEmail() {
    return sEmail;
  }

  public void setSEmail(String sEmail) {
    this.sEmail = sEmail;
  }


  public long getClassId() {
    return classId;
  }

  public void setClassId(long classId) {
    this.classId = classId;
  }


  @Override
  public String toString() {
    return "Student{" +
            "sId=" + sId +
            ", sName='" + sName + '\'' +
            ", sAge=" + sAge +
            ", sEmail='" + sEmail + '\'' +
            ", classId=" + classId +
            ", classes=" + classes +
            '}';
  }
}

2、修改Classes类,添加一个List students属性,使用一个List集合属性表示班级拥有的学生,如下:

package com.bruceliu.bean;


import java.util.List;

/**
 * 班级实体类  1的一方
 */
public class Classes {

  private long cId;
  private String cName;

  //表示含义 1个班级下有多个学生
  private List<Student> students; //学生集合  多的一方


  public long getCId() {
    return cId;
  }

  public void setCId(long cId) {
    this.cId = cId;
  }


  public String getCName() {
    return cName;
  }

  public void setCName(String cName) {
    this.cName = cName;
  }

  public List<Student> getStudents() {
    return students;
  }

  public void setStudents(List<Student> students) {
    this.students = students;
  }

  @Override
  public String toString() {
    return "Classes{" +
            "cId=" + cId +
            ", cName='" + cName + '\'' +
            ", students=" + students +
            '}';
  }
}

2.3.修改sql映射文件classMapper.xml

添加如下的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="com.bruceliu.mapper.ClassesMapper">

    <!--配置1对多 结果集映射-->
    <resultMap id="classMap" type="Classes">
        <!--主键-->
        <id property="cId" column="C_ID"/>
        <result property="cName" column="c_name"/>

        <!--配置一个包含关系 “有很多”关系 -->
        <collection property="students" ofType="Student">
            <id property="sId" column="s_id"/>
            <result property="sName" column="s_name"/>
            <result property="sAge" column="s_age"/>
            <result property="sEmail" column="s_email"/>
            <result property="classId" column="class_id"/>
        </collection>

    </resultMap>


    <select id="getById" resultMap="classMap">
        SELECT C.*,S.* FROM classes C INNER JOIN student S on C.c_id=S.class_id where C.c_id=#{classId}
    </select>


</mapper>

2.4. 编写单元测试类

package com.bruceliu.test;

import com.bruceliu.bean.Classes;
import com.bruceliu.mapper.ClassesMapper;
import com.bruceliu.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/**
 * @author bruceliu
 * @create 2019-07-09 10:06
 * @description 测试1对多
 */
public class TestOne2Many {

    SqlSession session=null;
    ClassesMapper classesMapper=null;

    @Before
    public void init(){
        session = MyBatisUtils.getSession();
        classesMapper = session.getMapper(ClassesMapper.class);
    }

    @Test
    public void test1(){
        Classes c = classesMapper.getById(1L);
        System.out.println(c);
    }

    @After
    public void destory(){
        session.close();
    }


}

2.5. MyBatis一对多关联查询总结

MyBatis中使用collection标签来解决一对多的关联查询,ofType属性指定集合中元素的对象类型。

5. 多对多关联(重点)

3.1 需求

在这里插入图片描述
在这里插入图片描述

3.2. 准备SQL语句

在这里插入图片描述

3.3 User实体类

package com.bruceliu.bean;


import java.util.List;

public class User {

  private long uId;
  private String uName;
  private String uSex;
  private long uAge;

  private List<Role> roles; //一个用户下面多个角色

  public long getUId() {
    return uId;
  }

  public void setUId(long uId) {
    this.uId = uId;
  }


  public String getUName() {
    return uName;
  }

  public void setUName(String uName) {
    this.uName = uName;
  }


  public String getUSex() {
    return uSex;
  }

  public void setUSex(String uSex) {
    this.uSex = uSex;
  }


  public long getUAge() {
    return uAge;
  }

  public void setUAge(long uAge) {
    this.uAge = uAge;
  }

  public List<Role> getRoles() {
    return roles;
  }

  public void setRoles(List<Role> roles) {
    this.roles = roles;
  }

  @Override
  public String toString() {
    return "User{" +
            "uId=" + uId +
            ", uName='" + uName + '\'' +
            ", uSex='" + uSex + '\'' +
            ", uAge=" + uAge +
            ", roles=" + roles +
            '}';
  }
}

3.4 Role实体类

package com.bruceliu.bean;


public class Role {

  private long rId;
  private String rName;


  public long getRId() {
    return rId;
  }

  public void setRId(long rId) {
    this.rId = rId;
  }


  public String getRName() {
    return rName;
  }

  public void setRName(String rName) {
    this.rName = rName;
  }


  @Override
  public String toString() {
    return "Role{" +
            "rId=" + rId +
            ", rName='" + rName + '\'' +
            '}';
  }
}

3.5 UserMapper

package com.bruceliu.mapper;

import com.bruceliu.bean.User;

/**
 * @author bruceliu
 * @create 2019-07-09 11:10
 * @description
 */
public interface UserMapper {

    //1.根据ID查询user(同时关联查询一下role集合信息)
    public User getUserByid(long uid);
}

3.6 UserMapper.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="com.bruceliu.mapper.UserMapper">

    <resultMap id="userMap" type="User">
        <id property="uId" column="u_id"/>
        <result property="uAge" column="u_age"/>
        <result property="uName" column="u_name"/>
        <result property="uSex" column="u_sex"/>

        <!--一个用户多个角色-->
        <collection property="roles" ofType="Role">
            <id property="rId" column="r_id"/>
            <result property="rName" column="r_name"/>
        </collection>

    </resultMap>
    
    
    <select id="getUserByid" resultMap="userMap">
        SELECT * FROM `user` U INNER JOIN role_user RU ON U.u_id=RU.uu__id INNER JOIN role R ON RU.rr_id=R.r_id
where U.u_id=#{uid}
    </select>

</mapper>

3.7 测试

package com.bruceliu.test;

import com.bruceliu.bean.Student;
import com.bruceliu.bean.User;
import com.bruceliu.mapper.StudentMapper;
import com.bruceliu.mapper.UserMapper;
import com.bruceliu.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/**
 * @author bruceliu
 * @create 2019-07-09 11:20
 * @description
 */
public class TesMany2Many {

    SqlSession session=null;
    UserMapper userMapper=null;

    @Before
    public void init(){
        session = MyBatisUtils.getSession();
        userMapper = session.getMapper(UserMapper.class);
    }

    /**
     *   测试根据人查询所属的角色集合
     */
    @Test
    public void test1(){
        User user = userMapper.getUserByid(1);
        System.out.println(user);
    }

    @After
    public void destory(){
        session.close();
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值