MyBatis一对多处理

MyBatis一对多处理

本节新建 MyBatis-07 项目学习 MyBatis 中的一对多处理。

1. 搭建测试环境

本节使用的数据库与上一节的数据库相同,配置文件啥的都是直接复制粘贴,但是实体类 Student 和 Teacher 要改变一下,对应的接口和配置文件内容也先删干净

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

实体类 Teacher 对应的 TeacherMapper 接口,只有一个根据 id 查询老师信息的方法

public interface TeacherMapper {
    // 获取指定 id 老师的信息 包含其所有的学生
    public Teacher getTeacher(int id);
}

在 TeacherMapper.xml 中给这个方法实现一下,只有一个参数,#{ } 随便取

<mapper namespace="com.qiyuan.dao.TeacherMapper">

    <select id="getTeacher" resultType="Teacher">
        select * from teacher where id = #{id}
    </select>

</mapper>

测试方法获取 id 为1的老师的信息,这里省略,结果

Teacher(id=1, name=祈鸢, students=null)

还是那个道理,没做结果集映射,students 肯定是空的啦。

2. 按照查询嵌套处理

和上节处理一对多类似,不过换成 collection 标签,这里还要注意 javaType 和 ofType 的区别( javaType 好像可以省略?)

<mapper namespace="com.qiyuan.dao.TeacherMapper">

    <!--查询对应的老师-->
    <select id="getTeacher" resultMap="TeacherStudent">
        select * from teacher where id = #{id}
    </select>

    <!--查出来就是个 Teacher 对象-->
    <resultMap id="TeacherStudent" type="Teacher">
        <!-- 一样的属性就不写了 -->
        <!--复杂的属性,需要单独处理;集合 collection-->
        <!-- property 属性名 即 List<Student> students -->
        <!-- javaType 指的是 java 类型,如此处是 ArrayList,ofType 指的是对应的泛型 -->
        <!--这里的 type 是 Teacher 所以 column 中的 id 自然也是指 Teacher.id-->
        <collection property="students" javaType="ArrayList" ofType="Student" column="id" select="getStudentByTeacherId"/>
    </resultMap>

    <!--子查询语句,怎么获得 id 呢?通过上面的 column 传进来-->
    <select id="getStudentByTeacherId" resultType="Student">
        select * from student where tid = #{id}
    </select>

</mapper>

执行测试方法,得到的结果

Teacher(id=0, name=祈鸢, 
        students=[Student(id=1, name=小明, tid=1), 
                  Student(id=2, name=小红, tid=1), 
                  Student(id=3, name=小张, tid=1), 
                  Student(id=4, name=小李, tid=1), 
                  Student(id=5, name=小王, tid=1)])

这里的 id=0 好像是因为 id 执行了子查询,被映射到 Student 里了···我也不太确定,后面再说吧。所以这里为了能正确映射,要添加

	...
    <resultMap id="TeacherStudent" type="Teacher">
        <!-- 一样的属性就不写了 -->
        <result property="id" column="id"/>
    	...

把查询到的 id 映射到老师的 id 中就正常了,还是少偷懒吧。

3. 按照结果嵌套处理

也是和之前一样,在接口中添加方法

public interface TeacherMapper {
	...
    // 获取指定 id 老师的信息 包含其所有的学生,按照结果嵌套处理
    public Teacher getTeacher2(int id);
}

再写这个方法使用的 SQL 语句和结果集映射

<mapper namespace="com.qiyuan.dao.StudentMapper">
    
    ...
    
    <!--按照结果嵌套处理-->
    <select id="getTeacher2" resultMap="TeacherStudent2">
        select s.id as sid, s.name as sname, t.id as tid, t.name as tname
        from student s, teacher t
        where s.tid = t.id and t.id = #{id}
    </select>

    <resultMap id="TeacherStudent2" type="Teacher">
        <!--这里也不能偷懒!否则报错
        Expected one result (or null) to be returned by selectOne() -->
        
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
        <!-- ofType 属性的泛型 -->
        <collection property="students" ofType="Student">
            <!--对应学生的属性-->
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>
    
</mapper>

查询到的结果,正确了

Teacher(id=1, name=祈鸢, 
        students=[Student(id=1, name=小明, tid=1), 
                  Student(id=2, name=小红, tid=1), 
                  Student(id=3, name=小张, tid=1), 
                  Student(id=4, name=小李, tid=1), 
                  Student(id=5, name=小王, tid=1)])

写 SQL 语句的时候麻烦了一点,但写映射的时候很简单···这里又因为偷懒没写 result,报错找了好一会。虽然目前不太清楚原因,但 result 该写的还是要写

4. 总结

两节把多对一和一对多的写法了解了一下

  • 多对一,用 association,关联一个
  • 一对多,用 collection,集合多个

还有 Type 的区别

  • javaType:属性在 java 中的类型,如 Student、Teacher 这种类型,或者 ArrayList 这种带泛型的容器类型
  • ofType:当 javaType 为 ArrayList 这种带泛型的容器类型时,就要写 ofType,即其中的泛型

还有几个比较重要的知识点

  • Mysql 引擎
  • InnoDB 底层原理
  • 索引、索引优化

本节没搞明白的就是 result 这东西到底什么时候可以省略不写

上一篇:华创期货:日内交易简单方法有效规避亏损


下一篇:MyBatis多对一处理