Mybatis学习日记-day6-多对一和一对多

一、学习目标

        在之前的博客里,学习的数据库模型都是单一的,还是那句话,如果世界总是那么美好就好了!在数据库设计和关系型数据建模中,多对一(Many-to-One)和一对多(One-to-Many)是两种非常基础且常见的实体间关系,它们是数据库设计中非常基础且强大的概念,它们帮助我们在逻辑上组织和表示现实世界中的复杂关系。

二、多对一

1.搭建测试环境

1.数据库

USE mybatis;
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, 'Mr.柳'); 
CREATE TABLE `student` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  `tid` INT(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fktid` (`tid`),
  CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');

2.实体类

@Data
public class Student {
    private int id;
    private String name;
    //多个学生可以是同一个老师,即多对一
    private Teacher teacher;
}
@Data
public class Teacher {
    private int id;
    private String name;
    //一个老师多个学生
    private List<Student> students;
}

3.mapper接口

public interface StudentMapper {
     //List<Student> selectStudent();
     //获取所有学生及对应老师的信息
     public List<Student> getStudents();
}
public interface TeacherMapper {
    //获取指定老师,及老师下的所有学生
    public Teacher getTeacher(int id);
}

4.嵌套 Select 查询

        在mybatis官方文件中提到,关联结果映射和其它类型的映射工作方式差不多。 你需要指定目标属性名以及属性的javaType(很多时候 MyBatis 可以自己推断出来),在必要的情况下你还可以设置 JDBC 类型,如果你想覆盖获取结果值的过程,还可以设置类型处理器。

        关联的不同之处是,你需要告诉 MyBatis 如何加载关联。MyBatis 有两种不同的方式加载关联:

1.嵌套 Select 查询:通过执行另外一个 SQL 映射语句来加载期望的复杂类型。

2.嵌套结果映射:使用嵌套的结果映射来处理连接结果的重复子集。

嵌套 Select 查询,
    <select id="getStudents" resultMap="StudentTeacher">
        select * from student
    </select>
    <resultMap id="StudentTeacher" type="Student">
        <association property="teacher"  column="{id=tid,name=tid}" javaType="Teacher" select="getTeacher"/>
    </resultMap>
    
    <select id="getTeacher" resultType="teacher">
        select * from teacher where id = #{id}
    </select>

        就是这么简单。我们有两个 select 查询语句:一个用来加载学生信息(student),另外一个用来加载老师(teacher),而且学生的结果映射描述了应该使用 getTeacher 语句加载它的 teacher属性。其它所有的属性将会被自动加载,只要它们的列名和属性名相匹配。

        然而,在mybatis官方文档中提到,这种方式虽然很简单,但在大型数据集或大型数据表上表现不佳。这个问题被称为“N+1 查询问题”。 概括地讲,N+1 查询问题是这样子的:

  • 你执行了一个单独的 SQL 语句来获取结果的一个列表(就是“+1”)。
  • 对列表返回的每条记录,你执行一个 select 查询语句来为每条记录加载详细信息(就是“N”)。

        这个问题会导致成百上千的 SQL 语句被执行。有时候,我们不希望产生这样的后果。

        好消息是,MyBatis 能够对这样的查询进行延迟加载,因此可以将大量语句同时运行的开销分散开来。 然而,如果你加载记录列表之后立刻就遍历列表以获取嵌套的数据,就会触发所有的延迟加载查询,性能可能会变得很糟糕。

        所以,我们需要学习另一种方法,也就是上面提到的:关联的嵌套结果映射。我将在之后一对多的学习中使用方法jieguo。

5.导入映射

    <mappers>
        <!--引入映射文件-->
        <mapper resource="Mapper/StudentMapper.xml"/>
        <!--mapper resource="mapper/TeacherMapper.xml"-->
    </mappers>

6.测试

 @Test
    public void testGetStudents(){
        SqlSession session = MybatisUtils.getSession();
        StudentMapper mapper = session.getMapper(StudentMapper.class);
        List<Student> students = mapper.getStudents();
        for (Student student : students){
            System.out.println(student);
        }
        session.close();
    }

结果:

三、一对多

1.搭建测试环境

1.实体类

@Data
public class Student {
    private int id;
    private String name;
    private int tid;
}
@Data
public class Teacher {
    private int id;
    private String name;
    //一个老师多个学生
    private List<Student> students;
}

2.嵌套结果映射

    <select id="getTeacher" resultMap="TeacherStudent">
        select s.id sid, s.name sname , t.name tname, t.id tid
        from student s,teacher t
        where s.tid = t.id and t.id=#{id}
    </select>
    <resultMap id="TeacherStudent" type="Teacher">
        <result  property="name" column="tname"/>
        <collection property="students" ofType="Student">
            <result property="id" column="sid" />
            <result property="name" column="sname" />
            <result property="tid" column="tid" />
        </collection>
    </resultMap>

  现在我们将学生表和老师表连接在一起,而不是执行一个独立的查询语句,注意查询中的连接,以及为确保结果能够拥有唯一且清晰的名字,我们设置的别名。 这使得进行映射非常简单。

3.导入映射

     <mappers>
        <!--引入映射文件-->
        <mapper resource="Mapper/StudentMapper.xml"/>
        <mapper resource="mapper/TeacherMapper.xml"/>
     </mappers>

4.测试

@Test
    public void testGetTeacher(){
        SqlSession session = MybatisUtils.getSession();
        TeacherMapper mapper = session.getMapper(TeacherMapper.class);
        Teacher teacher = mapper.getTeacher(1);
        System.out.println(teacher.getName());
        System.out.println(teacher.getStudents());
    }

结果:

      

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值