MyBatis框架处理一对多关系表中关联数据的方式(一次查询法和嵌套查询法)+使用注解标签写SQL+两个标签(association标签和collection标签)

一、准备工作

1、创建专业表和学生表

-- 创建学生表
CREATE TABLE student(
  id INT PRIMARY KEY AUTO_INCREMENT,
  NAME VARCHAR(10),
  gender CHAR(1),
  phone VARCHAR(15),
  majorid INT,
  adminid INT
)
-- 创建专业表
CREATE TABLE major(
  id INT PRIMARY KEY AUTO_INCREMENT,
  NAME VARCHAR(10)
)

2、为专业表和学生表创建对应的Java模型类

  • 创建学生类
package com.ffyc.mybatispro.model;

public class Student {
    private int id;
    private String name;
    private String gender;
    private String phone;
    private Major major;// 将一个学生的专业信息封装在这个学生的专业对象属性中
    private Admin admin;// 将一个学生的操作人信息封装在这个学生的操作人对象属性中

    public Student() {
    }

    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 String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public Major getMajor() {
        return major;
    }

    public void setMajor(Major major) {
        this.major = major;
    }

    public Admin getAdmin() {
        return admin;
    }

    public void setAdmin(Admin admin) {
        this.admin = admin;
    }

    @Override
    public String toString() {// 开发期间才会用到toString()方法,在程序运行期间此方法是用不上的
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", phone='" + phone + '\'' +
                ", major=" + major +
                ", admin=" + admin +
                '}';
    }
}
  • 关键问题-查询学生的专业姓名和专业编号

A.之前做学生宿舍管理系统的时候采用的是在学生类中添加两个属性用来接收学生的专业姓名和专业编号当关联属性多的时候此方法不适用

B. 在学生类中添加一个专业对象属性,用来存储该学生的专业信息,但在使用时需要程序员自己对专业信息进行封装

Major major=new Major();
major.setId(1);
major.setName("计算机");
student.setMajor(major);
  • 创建专业类
package com.ffyc.mybatispro.model;

import java.util.List;

public class Major {
    private int id;
    private String name;
    private List<Student> studentList;// 将一个专业的多个学生信息以学生对象的形式封装在这个专业的本专业学生集合对象中
    public Major() {

    }
    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 List<Student> getStudentList() {
        return studentList;
    }

    public void setStudentList(List<Student> studentList) {
        this.studentList = studentList;
    }

    @Override
    public String toString() {// 开发期间才会用到toString()方法,在程序运行期间此方法是用不上的
        return "Major{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", studentList=" + studentList +
                '}';
    }
}
  •  关键问题-查询本专业的学生信息

A. 之前做学生宿舍管理系统的时候为统计一个宿舍住了几个学生采用的是数据库技术,使用了分组连接函数

SELECT m.name,GROUP_CONCAT(s.name)
FROM major m LEFT JOIN student s ON m.id=s.majorid
GROUP BY m.name

二、填加Student功能模块的步骤

1、定义一个接口文件StudentDao.java

2、定义StudentDao.java接口文件的sql映射文件StudentMapper.xml

注意:在sql映射文件StudentMapper.xml中要将Mapper标签的namespace属性赋值为映射接口文件的全类名

3、在MyBatis框架的核心配置文件mybatis.xml中注册定义好的sql映射文件

<mapper resource="mappers/StudentMapper.xml"></mapper>

三、关联查询结果映射一一次查询法一个学生有一个专业)

autoMappingBehavior:指定MyBatis如何自动映射列到字段或属性

1、方式一:设置autoMappingBehavior的value值为PARTIAL,即保持autoMappingBehavior的默认值。

特点:resultMap中有嵌套映射时MyBatis的自动映射功能会失效

举例:查询指定id的学生的信息及其专业和操作人的信息

该例中由于有嵌套映射,因此MyBatis自动映射的功能将会失效,查询结果表中的每个列都必须自定义映射到类的对应属性上

核心代码:

<setting name="autoMappingBehavior" value="PARTIAL"/>
<resultMap id="studentMap" type="student">
          <id property="id" column="id"></id>
          <result property="name" column="sname"></result>
          <result property="gender" column="gender"></result>
          <result property="phone" column="phone"></result>
          <!-- 嵌套映射 处理Student类中的major对象类属性映射数据的问题-->
          <association property="major" javaType="Major">
               <id property="id" column="maid"></id>
               <result property="name" column="mname"></result>
          </association>
         <!-- 嵌套映射 处理Student类中的admin对象类属性映射数据的问题-->
          <association property="admin" javaType="Admin">
              <id property="id" column="aid"></id>
              <result property="account" column="account"></result>
          </association>
    </resultMap>
    <select id="findStudent" parameterType="int"  resultMap="studentMap">
           SELECT s.id,s.name sname,s.gender,s.phone,m.id maid,m.name mname,a.id aid,a.account
           FROM student s LEFT JOIN major m ON s.majorid=m.id
                          LEFT JOIN admin a ON s.adminid=a.id
           WHERE s.id = #{id}
    </select>
测试代码:
SqlSession sqlSession= MybatisUtil.getSqlSession();
StudentDao studentDao=sqlSession.getMapper(StudentDao.class);
Student student=studentDao.findStudent(3);
System.out.println(student);
sqlSession.close();

输出结果:

2、方式二:设置autoMappingBehavior的value值为FULL

(1)特点:MyBatis会完全进行自动映射

(2)问题:按照类名赋值,多个类中同名属性有可能被赋予相同值,导致数据错误

解决数据错误问题的方式:为类中不能与数据库对应结果表的列名进行自动映射的基本属性添加自定义映射,为类中与其嵌套属性中的属性同名的基本属性添加自定义映射,为类中的嵌套属性中的所有属性都添加自定义映射,嵌套属性中的所有属性都要被查询

(3)举例:查询指定id的学生的信息及其专业和操作人的信息

核心代码:

<setting name="autoMappingBehavior" value="FULL"/>
<resultMap id="studentMap" type="student">
          <id property="id" column="id"></id>
          <result property="name" column="sname"></result>
          <result property="gender" column="gender"></result>
          <!-- 嵌套映射 处理Student类中的major对象类属性映射数据的问题-->
          <association property="major" javaType="Major">
               <id property="id" column="maid"></id>
               <result property="name" column="mname"></result>
          </association>
         <!-- 嵌套映射 处理Student类中的admin对象类属性映射数据的问题-->
          <association property="admin" javaType="Admin">
              <id property="id" column="aid"></id>
              <result property="account" column="account"></result>
              <result property="gender" column="agender"></result>
          </association>
    </resultMap>
    <select id="findStudent" parameterType="int"  resultMap="studentMap">
           SELECT s.id,s.name sname,s.gender,s.phone,m.id maid,m.name mname,a.id aid,a.account,a.gender agender
           FROM student s LEFT JOIN major m ON s.majorid=m.id
                          LEFT JOIN admin a ON s.adminid=a.id
           WHERE s.id = #{id}
    </select>

测试代码:

SqlSession sqlSession= MybatisUtil.getSqlSession();
StudentDao studentDao=sqlSession.getMapper(StudentDao.class);
Student student=studentDao.findStudent(3);
System.out.println(student);
sqlSession.close();

结果输出:

3、association标签

(1)property属性:其值是resultMap标签的返回值类型中的嵌套属性的属性名

(2)javaType属性:其值是resultMap标签的返回值类型中的嵌套属性的类型

(3)association标签里面的id标签和result标签与resultMap标签中的id标签和result标签用法一样

(4)select属性:其值某个select语句的id

(5)column属性:其值是上一级查询出来的外键名,用来传递外键的值

四、关联查询结果映射-嵌套查询法一个学生有一个专业)

举例:查询指定id的学生的信息及其专业和操作人的信息(先查出主表的数据再通过查询出来的外键查出关联表中的数据,逐级实现数据的封装)

1、核心代码:

    <resultMap id="studentMap1" type="Student">
        <id property="id" column="id"></id>
        <result property="name" column="sname"></result>
        <result property="gender" column="gender"></result>
        <result property="phone" column="phone"></result>
        <association property="major" javaType="Major"
                     select="findMajorById" column="majorid"></association>
        <association property="admin" javaType="Admin"
                     select="findAdminById" column="adminid"></association>
    </resultMap>
    <select id="findStudent" parameterType="int"  resultMap="studentMap1">
          select * from student where id = #{id}
    </select>
    <select id="findMajorById" resultType="Major">
          select id,name from major where id = #{majorid}
    </select>
    <select id="findAdminById" resultType="Admin">
          select id,account from admin where id = #{adminid}
    </select>

2、测试代码:

        SqlSession sqlSession= MybatisUtil.getSqlSession();
        StudentDao studentDao=sqlSession.getMapper(StudentDao.class);
        Student student=studentDao.findStudent(3);
        System.out.println(student);
        sqlSession.close();

3、结果输出:

 五、关联查询结果映射-一次查询法/嵌套查询法(一个专业有多个学生)

1、举例:根据id的值查询一个专业信息及其关联的学生对象的信息

(1)使用MySQL数据库技术可能会将单个专业信息查出来多条记录(即相同的同一专业信息在结果中出现多次)

代码:

SELECT m.id,m.name mname,s.name sname
   FROM major m LEFT JOIN student s ON m.id=s.majorid 
   WHERE m.id=1

结果输出:

(2)使用MyBatis框架(一次查询法

核心代码:

<resultMap id="majorMap" type="Major">
         <id property="id" column="id"></id>
         <result property="name" column="mname"></result>
         <!--一个专业对应有多名学生-->
         <collection property="studentList" javaType="list" ofType="Student">
             <result property="name" column="sname"></result>
         </collection>
    </resultMap>

    <select id="findMajorById" parameterType="int" resultMap="majorMap">
         SELECT m.id,m.name mname,s.name sname
         FROM major m LEFT JOIN student s ON m.id=s.majorid
         WHERE m.id = #{id}
    </select>

测试代码:

        SqlSession sqlSession= MybatisUtil.getSqlSession();
        MajorDao majorDao=sqlSession.getMapper(MajorDao.class);
        Major major=majorDao.findMajorById(1);
        System.out.println(major);
        sqlSession.close();

结果输出:

2、举例:查询所有的专业的信息及其关联的学生对象的信息(一次查询方式

核心代码:

<resultMap id="majorMap" type="Major">
         <id property="id" column="id"></id>
         <result property="name" column="mname"></result>
         <!--一个专业对应有多名学生-->
         <collection property="studentList" javaType="list" ofType="Student">
             <result property="name" column="sname"></result>
         </collection>
</resultMap>
<select id="findMajors" resultType="com.ffyc.mybatispro.model.Major" resultMap="majorMap">
         SELECT m.id,m.name mname,s.name sname
         FROM major m LEFT JOIN student s ON m.id=s.majorid
</select>

测试代码:

SqlSession sqlSession= MybatisUtil.getSqlSession();
MajorDao majorDao=sqlSession.getMapper(MajorDao.class);
List<Major>list=majorDao.findMajors();
System.out.println(list);
sqlSession.close();

结果输出:

3、举例:查询所有的专业的信息及其关联的学生对象的信息(嵌套查询法

核心代码:

<resultMap id="majorMap1" type="Major">
         <id property="id" column="id"></id>
         <result property="name" column="name"></result>
         <collection property="studentList" javaType="list" ofType="Student" select="findStudentById" column="id"></collection>
    </resultMap>
    <select id="findMajors1" resultMap="majorMap1">
         SELECT id,NAME FROM major
    </select>
    <select id="findStudentById" resultType="Student">
        SELECT NAME FROM student WHERE majorid = #{id}
    </select>

测试代码:

        SqlSession sqlSession= MybatisUtil.getSqlSession();
        MajorDao majorDao=sqlSession.getMapper(MajorDao.class);
        List<Major>list=majorDao.findMajors1();
        System.out.println(list);
        sqlSession.close();

调试结果输出:

4、collection标签(集合标签)

(1)property属性:其值是嵌套集合属性的属性名

(2) javaType属性:其值是嵌套集合属性的类型

(3)ofType属性:其值是嵌套集合属性中的元素的类型

(4)collection标签内部的id标签和result均是对ofType属性的值的属性进行映射

(5)select属性:其值是另一条select语句的id属性的值,用于在子级调用一次另一条select语句

(6)column属性:其值是select属性所调用的另一条select语句的参数

六、使用注解标签写SQL

1、在定义接口方法的时候,我们可以直接在接口方法的上方使用注解标签写SQL

2、非常建议在SQL比较简单的情况下使用注解标签写SQL,但是当SQL比较复杂的情况下还是建议使用在Mapper.xml接口配置文件中使用insert等标签写SQL

3、举例:

(1)注解标签-@Insert

核心代码:

@Insert("insert into student(name,gender,phone)value(#{name},#{gender},#{phone}) ")
    void saveStudent(Student student);

(2)注解标签-@Delete

核心代码:

@Delete("delete from student where id = #{id}")
    void deleteStudent(int id);// 删除指定id的学生

(3)注解标签-@Update

核心代码:

@Update("update student set name=#{name},phone=#{phone} where id = #{id}")
    void updateStudent(Student student);// 修改指定id的学生的信息

(4)注解标签-@Select

核心代码:

@Select("select * from student where id = #{id} ")
    Student findStudent1(int id);// 查询对应id的学生

5、复杂的Select查询语句-@Results、@Result

核心代码:

@Select("select * from student where id = #{id} ")
    @Results(id="studentMap2",value={
            @Result(column = "gen",property = "gender")
    })
    Student findStudent1(int id);// 查询对应id的学生

解析:

@Results等效于resultMap,他们的功能都是通过自定义映射封装数据

@Result用于封装一条映射(即从一个列到一个属性)

  • 18
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值