07-Mybatis基础之多对一和一对多的处理

多对一和一对多的处理

1、环境搭建

一对多和多对一的理解是相互的,譬如:一个班级里有一个班主任,一个班主任带多个学生:在学生的角度而言:为多个学生对应一个老师:即多对一;在老师的角度而言:为一个老师对应多个学生:即一对多。

环境搭建步骤:

  1. 创建数据库表:student表和teacher表,并插入数据,对应的sql语句如下:
# 创建teacher表 字段包括id和name
CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

#插入数据
INSERT INTO teacher(`id`, `name`) VALUES (1, '王老师');

# 创建student表,id,name和tid(student和teacher表进行关联,teacher表中的id作为student表中tid的外键)
CREATE TABLE `student` (
`id` INT(20) NOT NULL,
`name` VARCHAR(50) DEFAULT NULL,
`tid` INT(20) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fktid` (`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

#给student表插入数据
INSERT INTO `student` (`id`, `name`, `tid`) VALUES
('1', '张三', '1'),
('2', '李四', '1'),
('3', '王五', '1'),
('4', '赵六', '1'), 
('5', '田七', '1');
  1. 创建maven的子模块:在pom文件中引入Lombok的maven依赖:
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.22</version>
</dependency>
  1. 新建student和teacher实体类
package com.kevin.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author : kevin ding
 * @date : 2022/1/15 15:08
 * @description : 对应于数据库表student的实体类
 */

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {

    private int id;
    private String name;

    // 关联老师(直接关联老师的对象)
    private Teacher teacher;
}
package com.kevin.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author : kevin ding
 * @date : 2022/1/15 15:07
 * @description : 对应数据库中的实体类Teacher
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {

    private int id;
    private String name;
}
  1. 编写实体类对应的StudentMapper,TeacherMapper接口和对应的StudentMapper.xml,TeacherMapper.xml

StudentMapper接口:

package com.kevin.dao;

/**
 * @author : kevin ding
 * @date : 2022/1/15 15:06
 * @description :
 */
public interface StudentMapper {
}

TeacherMapper接口:

package com.kevin.dao;
/**
 * @author : kevin ding
 * @date : 2022/1/15 15:06
 * @description :
 */
public interface TeacherMapper {
}

StudentMapper.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">
<!-- namespace:绑定该mapper.xml与那个接口相关联(类似于UserDaoImpl中的implement实现哪个接口)-->
<mapper namespace="com.kevin.dao.StudentMapper">

</mapper>

TeacherMapper.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">
<!-- namespace:绑定该mapper.xml与那个接口相关联(类似于UserDaoImpl中的implement实现哪个接口)-->
<mapper namespace="com.kevin.dao.TeacherMapper">

</mapper>
  1. 测试搭建环境是否能够运行:
  • 直接通过注解方式,在TeacherMapper中编写对应的方法:
package com.kevin.dao;

import com.kevin.pojo.Teacher;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

/**
 * @author : kevin ding
 * @date : 2022/1/15 15:06
 * @description :
 */
public interface TeacherMapper {
    @Select("select * from teacher where id = #{tid}")
    Teacher getTeacher(@Param("tid") int id);
}

测试类:

package com.kevin.dao;

import com.kevin.pojo.Teacher;
import com.kevin.utils.MybatisUtils;
import com.mysql.cj.jdbc.MysqlDataSource;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

/**
 * @author : kevin ding
 * @date : 2022/1/15 15:15
 * @description :
 */
public class MyTest {

    @Test
    public void test1(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacher = mapper.getTeacher(1);
        System.out.println(teacher);
        sqlSession.close();

    }
}

成功运行,项目环境搭建完毕,下面进行多对一和一对多的学习!

2、 多对一处理:

多对一的查询方法有两种:

  • 按查询嵌套
  • 按结果嵌套

2.1 按查询嵌套

多对一的查询:以查询全部学生信息为例:

在原始的查询方法中:

  1. StudentMapper接口中编写抽象方法:
// 查询所有学生信息
List<Student> getAllStudents();
  1. 创建StudentMapper.xml中编写select的sql语句:
<select id="getAllStudents" resultType="Student">
    select * from student;
</select>
  1. 测试:
@Test
public void getAllStudents(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    List<Student> allStudentsList = mapper.getAllStudents();
    for (Student student : allStudentsList) {
        System.out.println(student);
    }
}
  1. 查询结果显示:数据中的teacher字段为null
    请添加图片描述

当数据中出现其他引用对象时,需要进行关联属性:

  • association: 关联对象属性类型
  • collections:关联集合类型

按查询嵌套处理方法:(主要是对StudentMapper.xml进行修改)

  1. 先查询student表中的所有信息
  2. 对于student表的结果进行映射
  3. 根据student表中的tid去查询对应teacher表中的id值

编写的StudentMapper.xml中:

<!--1. 查询学生表-->
<select id="getAllStudents" resultMap="StudentAndTeacher">
    select * from student;
</select>

<!--2. 对应的resultMap 类型为Student,进行student的结果集映射-->
    <resultMap id="StudentAndTeacher" type="Student">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <!--association关联属性 property属性名 column为在student表中的列名 javaType属性类型 select为根据tid要查询的语句-->
        <association property="teacher" column="tid" javaType="Teacher" select="getTeachers"/>
    </resultMap>

<!--3. 根据查询学生表所得的tid,去老师表中查询对应的信息-->
    <select id="getTeachers" resultType="Teacher">
        select * from teacher where id = #{id};
    </select>

查询结果:成功将teacher属性以对象的形式显示
请添加图片描述

2.2 按结果嵌套

按结果嵌套处理方法步骤:

  • 首先编写连表查询的sql语句,将正确的需求查询出来
  • 再根据查询的结果,对结果集通过ResultMap进行映射
  1. Mapper接口中添加查询所有学生信息的抽象方法:
// 第二种方法 按结果嵌套
List<Student> getAllStudents2();
  1. StudentMapper.xml中编写对应的sql查询和结果集映射
<!--方法2:(目前项目中较为常见的方法)按结果嵌套查询, 先通过sql连表查询出所需要的结果,再对结果进行映射-->
<select id="getAllStudents2" resultMap="StudentAndTeacher2">
    select s.id as sid, s.name as sname, t.name as tname
    from student as s, teacher as t 
    where s.tid = t.id
</select>

<!--对getAllStudents2的查询结果ResultMap进行结果集映射,类型为Student类型-->
<resultMap id="StudentAndTeacher2" type="Student">
    <!--column中的值为查询语句中对列起的别名-->
    <result property="id" column="sid"/>
    <result property="name" column="sname"/>
    <!--关联对象property 关联对象在Student实体类中的属性 javaType为对应的java类型-->
    <association property="teacher" javaType="Teacher">
        <!--在association标签内部 再将其他属性和字段名进行对应-->
        <result property="name" column="tname"/>
    </association>
</resultMap>
  1. 测试:
@Test
public void getAllStudents2(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    List<Student> allStudentsList = mapper.getAllStudents2();
    for (Student student : allStudentsList) {
        System.out.println(student);
    }
}
  1. 运行结果显示:
    请添加图片描述

3、一对多处理:

同理,对于Teacher而言,一个老师带有多个学生,即一对多。

  1. 搭建环境:创建一个maven模块:于多对一的环境几乎一致,改动地方为:

对于Teacher和Student两个实体类进行改动:

Teacher类:一个老师关联多个学生

package com.kevin.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

/**
 * @author : kevin ding
 * @date : 2022/1/15 17:23
 * @description : 对应数据库中的实体类Teacher
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {

    private int id;
    private String name;
    // 一个老师下面有多个学生,需要关联学生列表
    private List<Student> students;
}

Student类中,一个学生对应一个老师,直接写属性就行

package com.kevin.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author : kevin ding
 * @date : 2022/1/15 17:20
 * @description : 对应于数据库表student的实体类
 */

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {

    private int id;
    private String name;
    // 每个学生只有一个老师,只需写其tid属性
    private int tid;
}

与多对一相同,一对多也有两种处理方法:

  • 按查询嵌套处理
  • 按结果嵌套处理

3.1 按查询嵌套处理

  1. TeacherMapper接口编写抽象方法:查询指定老师的信息:
// 第一种 按照查询进行处理
Teacher getTeacher1(@Param("id") int id);
  1. TeacherMapper.xml编写sql语句:
<!--1. 查询指定id的老师信息-->
<select id="getTeacher1" resultMap="TeacherAndStudent1">
    select *
    from teacher
    where id = #{id};
</select>

<!--2. 结果集映射-->
<resultMap id="TeacherAndStudent1" type="Teacher">
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    <!--collection中需要填写属性students的类型javaType:list, 并且list中的泛型也要表明:ofType表示  select标签表示要去执行哪个查询方法,column中的值为老师的id,并将其传给select标签中查询所需要的字段值-->
    <collection property="students" javaType="ArrayList" ofType="Student" select="getStudentsByTeacherId" column="id"/>
</resultMap>

<!--3.根据Id查询学生信息-->
<select id="getStudentsByTeacherId" resultType="Student">
    select *
    from student
    where tid = #{tid};
</select>
  1. 测试类编写:
@Test
public void getTeacher1(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
    Teacher teacher = mapper.getTeacher1(1);
    System.out.println(teacher);
    sqlSession.close();
}

4. 结果:
![请添加图片描述](https://img-blog.csdnimg.cn/a2162fdf81fc44cc84af36c0be9b6d5d.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAS2V2aW4tRGluZw==,size_20,color_FFFFFF,t_70,g_se,x_16)



### 3.2 按结果嵌套处理

1. TeacherMapper接口编写抽象方法:查询指定老师的信息:

```java
// 第二种 按照结果进行嵌套处理
Teacher getTeacher2(@Param("id") int id);
  1. TeacherMapper.xml编写sql语句:
<!--根据结果进行嵌套查询-->
<!--1. 首先连表查询出所需要的结果-->
<select id="getTeacher2" resultMap="TeacherAndStudent2">
    select s.id as sid, s.name as sname, t.id as tid, t.name as tname
    from student as s, teacher as t
    where s.tid = t.id and t.id = #{id}
</select>

<!--进行结果集映射
    对于集合的话,使用collection!
      collection标签中的JavaType和ofType都是用来指定对象类型的
           JavaType是用来指定pojo中属性的类型
           ofType指定的是映射到list集合属性中pojo的类型。
 -->
<resultMap id="TeacherAndStudent2" type="Teacher">
    <result property="id" column="tid"/>
    <result property="name" column="tname"/>
    <collection property="students" ofType="Student">
        <!--collection中将student的属性映射出来-->
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="tid" column="tid"/>
    </collection>
</resultMap>
  1. 测试类编写:
@Test
public void getTeacher2(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
    Teacher teacher = mapper.getTeacher2(1);
    System.out.println(teacher);
    sqlSession.close();
}
  1. 运行结果:
    请添加图片描述

4、总结

  1. 结果集映射中,关联属性-association,关联集合-collection
  2. association是用于一对一和多对一,而collection是用于一对多的关系
  3. javaType和ofType都是用来指定对象类型的,javaType是用来指定pojo中属性的类型,ofType指定的是映射到list集合属性中pojo的类型。

需要注意的几点:

  • 保证SQL的可读性,尽量通俗易懂

  • 根据实际要求,尽量编写性能更高的SQL语句

  • 注意属性名和字段不一致的问题

  • 注意一对多和多对一 中:字段和属性对应的问题

  • 尽量使用Log4j,通过日志来查看自己的错误

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值