Myatis 系列之 一对多、多对一 及 ResultMap的使用

54 阅读7分钟

我 | 在这里
🕵️ 读书 | 长沙 ⭐软件工程 ⭐ 本科
🏠 工作 | 广州 ⭐ Java 全栈开发(软件工程师)
🎃 爱好 | 研究技术、旅游、阅读、运动、喜欢流行歌曲
🏷️ 标签 | 男 自律狂人 目标明确 责任心强
✈️公众号 | 热爱技术的小郑
🚀 邮箱 | 2977429967@qq.com
✈️ GitHub项目仓库 开源项目 + 实战Demo  

为何而写?
🍍 好记性不如烂笔头,记录学习的相关知识 、项目 BUG 解决
🍇 复盘总结,加深记忆,方便自己查看
🍑 分享知识,咱就是这么乐于助人、专注填坑20年、哈哈哈哈

目标描述
🏆 没有伞的孩子、只能用力奔跑。向着架构师的方向努力、做一个有始有终的人。

前言

项目源码位置:GitHub 传送门 在Mybatis中,可以使用resultMap(结果集映射)作为sql的返回类型

一般用来解决如下问题:

  • 数据库表字段名和实体类属性名不一致的问题;
  • 多对一问题:
    • 例如:多个学生对应同一个老师,查询每个学生信息(包含老师对象属性)
  • 一对多问题:
    • 例如:一个老师教学多个学生,查询某个老师信息及其属下学生(包含学生列表)

1、字段名和属性名不一致问题

单纯的实体类字段和数据库字段不一致问题,较为简单。不在给出搭建环境的过程。

     *          实体类字段           数据库字段
     *             id                 id
     *         goods_Name            name
     *         goods_Amount         amount
     *         goods_Price           price
    3、通过结果集映射
    <select id="queryGoodsById" resultMap="GoodsMap">
           select *
           from goods
           where id = #{id}
    </select>

    <!--  结果集映射  -->
    <resultMap id="GoodsMap" type="Goods">
        <!--column数据库中的字段,property实体类中的属性-->
        <result column="id" property="id" />
        <result column="name" property="goods_Name" />
        <result column="amount" property="goods_Amount" />
        <result column="price" property="goods_Price" />
    </resultMap>

测试单元

  /**
     * @description: 测试查询商品信息 数据库字段 和 实体类字段不一致问题
     * @author: zhengyuzhu
     * @date: 2023/11/22 9:19
     **/
    @Test
    public void testDemo1(){
        //第一步:获得SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        //方式一:getMapper
        GoodsMapper goodsMapper = sqlSession.getMapper(GoodsMapper.class);
        Goods goods = goodsMapper.queryGoodsById(1001);
        System.out.println(goods);

        //关闭SqlSession
        sqlSession.close();

        /**
         *  输出如下 :
         *          实体类字段           数据库字段
         *             id                 id
         *         goods_Name            name
         *         goods_Amount         amount
         *         goods_Price           price
         *
         *  Goods{id=1001, goods_Name='null', goods_Amount=null, goods_Price=null}
         *
         *
         *
         *  第一种方式:字段起别名:
         *            select id,name as goods_Name,amount as goods_Amount,price as goods_Price
         *
         *  Goods{id=1001, goods_Name='茶杯', goods_Amount=10, goods_Price=13.6}
         *
         *
         *  第二种方式:结果集映射:
         *              具体实现查看 GoodsMapper.xml 文件注释描述
         *
         *  Goods{id=1001, goods_Name='茶杯', goods_Amount=10, goods_Price=13.6}
         *
         **/
    }

2 、环境搭建

创建 学生表 和 教师表、插入数据

CREATE TABLE `tb_teacher` (
	`id` INT(10) NOT NULL,
	`name` VARCHAR(30) DEFAULT NULL,
	PRIMARY KEY (`id`)
)ENGINE = INNODB DEFAULT CHARSET=utf8

INSERT INTO tb_teacher(`id`,`name`) VALUES (1,'玉小刚');

CREATE TABLE `tb_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 `tb_student`(`id`,`name`,`tid`) VALUES ('1','唐三','1');
INSERT INTO `tb_student`(`id`,`name`,`tid`) VALUES ('2','小舞','1');
INSERT INTO `tb_student`(`id`,`name`,`tid`) VALUES ('3','戴沐白','1');
INSERT INTO `tb_student`(`id`,`name`,`tid`) VALUES ('4','朱朱清','1');
INSERT INTO `tb_student`(`id`,`name`,`tid`) VALUES ('5','奥斯卡','1');
INSERT INTO `tb_student`(`id`,`name`,`tid`) VALUES ('6','宁荣荣','1');
INSERT INTO `tb_student`(`id`,`name`,`tid`) VALUES ('7','马红俊','1');
INSERT INTO `tb_student`(`id`,`name`,`tid`) VALUES ('8','白尘香','1');

3、多对一处理

获得所有学生及其对应老师(多个学生对应一个老师)

学生类

@Data                              //get,set
@NoArgsConstructor                 //无参构造
@AllArgsConstructor                //有参构造
public class Student {
    private Integer id;
    private String name;
    private Teacher teacher;

}

教师类

@Data                              //get,set
@NoArgsConstructor                 //无参构造
@AllArgsConstructor                //有参构造
public class Teacher {
    private Integer id;
    private String name;

}

mybatis 核心配置文件

这个根据自己设置加载

   别名
    <typeAliases>
        <package name="com.zyz.mybatis.entity" />
    </typeAliases>

   映射器
    <mappers>
        <mapper resource="com/zyz/mybatis/mapper/StudentMapper.xml"/>
    </mappers>

有两种方式处理多对一关系

  • 1、按照结果集嵌套处理
  • 2、按照查询嵌套处理

1、按照结果集嵌套处理

    <!--
        1、按照结果集嵌套处理
            这里重点说一下 这个结果集映射。如果对查询出来的数据字段 起了 别名。则映射的时候 要用这个别名。
    -->
    <resultMap id="StudentMap" type="Student">
        <!--这里的column是与查询结果的字段名对应,字段重命名了则对应命名后的字段-->
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <!--复杂的属性需要单独处理 对象:association  集合:collection-->
        <association property="teacher" javaType="Teacher">
            <result property="name" column="tname"/>
            <result property="id" column="tid"/>
        </association>
    </resultMap>

    <!--查询学生-->
    <select id="getStudent" resultMap="StudentMap">
        select s.id sid,s.name sname,t.name tname,s.tid tid
        from tb_student s
        join tb_teacher t
        on s.tid = t.id
    </select>

测试单元

    /**
     * @description: 1、按照结果集嵌套处理  多对一
     * @author: zhengyuzhu
     * @date: 2023/11/22 23:07
     **/
    @Test
    public void testDemo1(){
        //第一步:获得SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> studentList = studentMapper.getStudent();

        for(Student student : studentList){
            System.out.println(student);
        }

        sqlSession.close();

        /**
         * 输出如下:
         *
         * [com.zyz.mybatis.mapper.StudentMapper.getStudent]-==>  Preparing: select s.id sid,s.name sname,t.name tname,s.tid tid from tb_student s join tb_teacher t on s.tid = t.id
         * [com.zyz.mybatis.mapper.StudentMapper.getStudent]-==> Parameters:
         * [com.zyz.mybatis.mapper.StudentMapper.getStudent]-<==      Total: 8
         * Student{id=1, name='唐三', teacher=Teacher{id=1, name='玉小刚'}}
         * Student{id=2, name='小舞', teacher=Teacher{id=1, name='玉小刚'}}
         * Student{id=3, name='戴沐白', teacher=Teacher{id=1, name='玉小刚'}}
         * Student{id=4, name='朱朱清', teacher=Teacher{id=1, name='玉小刚'}}
         * Student{id=5, name='奥斯卡', teacher=Teacher{id=1, name='玉小刚'}}
         * Student{id=6, name='宁荣荣', teacher=Teacher{id=1, name='玉小刚'}}
         * Student{id=7, name='马红俊', teacher=Teacher{id=1, name='玉小刚'}}
         * Student{id=8, name='白尘香', teacher=Teacher{id=1, name='玉小刚'}}
         *
         **/
    }

2、按照查询嵌套处理

    <!--
        2、 按照查询嵌套处理
    -->

    <select id="getStudent2" resultMap="StudentMap2">
        select *  from tb_student;
    </select>

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

    <!--这里将学生和对应老师分开查询,将查询结果组合-->
    <resultMap id="StudentMap2" type="Student">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
    </resultMap>

测试单元

    /**
     * @description: 2、 按照查询嵌套处理  多对一
     * @author: zhengyuzhu
     * @date: 2023/11/22 23:07
     **/
    @Test
    public void testDemo2(){
        //第一步:获得SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> studentList = studentMapper.getStudent2();

        for(Student student : studentList){
            System.out.println(student);
        }

        sqlSession.close();

        /**
         * 输出如下:
         *
         * [com.zyz.mybatis.mapper.StudentMapper.getStudent2]-==>  Preparing: select * from tb_student;
         * [com.zyz.mybatis.mapper.StudentMapper.getStudent2]-==> Parameters:
         * [com.zyz.mybatis.mapper.StudentMapper.getTeacher]-====>  Preparing: select * from tb_teacher where id = ?;
         * [com.zyz.mybatis.mapper.StudentMapper.getTeacher]-====> Parameters: 1(Integer)
         * [com.zyz.mybatis.mapper.StudentMapper.getTeacher]-<====      Total: 1
         * [com.zyz.mybatis.mapper.StudentMapper.getStudent2]-<==      Total: 8
         * Student{id=1, name='唐三', teacher=Teacher{id=1, name='玉小刚'}}
         * Student{id=2, name='小舞', teacher=Teacher{id=1, name='玉小刚'}}
         * Student{id=3, name='戴沐白', teacher=Teacher{id=1, name='玉小刚'}}
         * Student{id=4, name='朱朱清', teacher=Teacher{id=1, name='玉小刚'}}
         * Student{id=5, name='奥斯卡', teacher=Teacher{id=1, name='玉小刚'}}
         * Student{id=6, name='宁荣荣', teacher=Teacher{id=1, name='玉小刚'}}
         * Student{id=7, name='马红俊', teacher=Teacher{id=1, name='玉小刚'}}
         * Student{id=8, name='白尘香', teacher=Teacher{id=1, name='玉小刚'}}
         *
         **/
    }

4、一对多处理

按指定ID查询老师及其所管理的学生(一个老师对应多个学生) StudentT类

@Data                              //get,set
@NoArgsConstructor                 //无参构造
@AllArgsConstructor                //有参构造
public class StudentT {
    private Integer id;
    private String name;
    private Integer tid;

}

Teacher类

@Data                              //get,set
@NoArgsConstructor                 //无参构造
@AllArgsConstructor                //有参构造
public class TeacherT {
    private Integer id;
    private String name;
    private List<StudentT> studentTs;

}

mybatis 核心配置文件

这个根据自己设置加载

   别名
    <typeAliases>
         <package name="com.zyz.mybatis.vo" />
    </typeAliases>

   映射器
    <mappers>
        <mapper resource="com/zyz/mybatis/mapper/TeacherMapper.xml"/>
    </mappers>

有两种方式处理一对多关系

  • 1、按照结果集嵌套处理
  • 2、按照查询嵌套处理

1、按照结果集嵌套处理

    <!--
        1、 按结果嵌套查询
    -->
    <select id="getTeacherById" resultMap="TeacherById">
        select t.id id, t.name tname, s.id sid,s.name sname,s.tid tid
        from tb_teacher t
                 join tb_student s
                      on t.id = s.tid;
    </select>

    <resultMap id="TeacherById" type="TeacherT">
        <result property="id" column="id"/>
        <result property="name" column="tname"/>
        <!--获取List<Student>中的泛型使用 ofType-->
        <collection property="studentTs" ofType="StudentT" javaType="java.util.List">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>

测试单元

    /**
     * @description: 1、 按结果嵌套查询  一对多
     * @author: zhengyuzhu
     * @date: 2023/11/22 23:07
     **/
    @Test
    public void testDemo3(){
        //第一步:获得SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        TeacherMapper teacherMapper = sqlSession.getMapper(TeacherMapper.class);
        TeacherT teacher = teacherMapper.getTeacherById(1);

        System.out.println(teacher);

        sqlSession.close();

        /**
         * 输出如下:
         *
         [org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 1486566962.
         [com.zyz.mybatis.mapper.TeacherMapper.getTeacherById]-==>  Preparing: select t.id id, t.name tname, s.id sid,s.name sname,s.tid tid from tb_teacher t join tb_student s on t.id = s.tid;
         [com.zyz.mybatis.mapper.TeacherMapper.getTeacherById]-==> Parameters:
         [com.zyz.mybatis.mapper.TeacherMapper.getTeacherById]-<==      Total: 8
         TeacherT(id=1, name=玉小刚, studentTs=[
                                               StudentT(id=1, name=唐三, tid=1),
                                               StudentT(id=2, name=小舞, tid=1),
                                               StudentT(id=3, name=戴沐白, tid=1),
                                               StudentT(id=4, name=朱朱清, tid=1),
                                               StudentT(id=5, name=奥斯卡, tid=1),
                                               StudentT(id=6, name=宁荣荣, tid=1),
                                               StudentT(id=7, name=马红俊, tid=1),
                                               StudentT(id=8, name=白尘香, tid=1)
                                               ])
         [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@589b3632]
         *
         **/
    }

2、按照查询嵌套处理

    <!--
         2、按照查询嵌套处理
    -->
    <select id="getTeacher2" resultMap="TeacherStudent2">
        select * from tb_teacher where id = #{tid}
    </select>

    <resultMap id="TeacherStudent2" type="TeacherT">
        <result property="id" column="id"/>
        <collection property="studentTs" javaType="java.util.List" ofType="StudentT" select="getStudentByTeacherId" column="id"/>
    </resultMap>

    <select id="getStudentByTeacherId" resultType="StudentT">
        select * from  tb_student where tid = #{tid}
    </select>

测试单元

    /**
     * @description: 2、 按照查询嵌套处理  一对多
     * @author: zhengyuzhu
     * @date: 2023/11/22 23:07
     **/
    @Test
    public void testDemo4(){
        //第一步:获得SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        TeacherMapper teacherMapper = sqlSession.getMapper(TeacherMapper.class);
        TeacherT teacher = teacherMapper.getTeacher2(1);

        System.out.println(teacher);

        sqlSession.close();

        /**
         * 输出如下:
         *
         [org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 1486566962.
         [com.zyz.mybatis.mapper.TeacherMapper.getTeacher2]-==>  Preparing: select * from tb_teacher where id = ?
         [com.zyz.mybatis.mapper.TeacherMapper.getTeacher2]-==> Parameters: 1(Integer)
         [com.zyz.mybatis.mapper.TeacherMapper.getStudentByTeacherId]-====>  Preparing: select * from tb_student where tid = ?
         [com.zyz.mybatis.mapper.TeacherMapper.getStudentByTeacherId]-====> Parameters: 1(Integer)
         [com.zyz.mybatis.mapper.TeacherMapper.getStudentByTeacherId]-<====      Total: 8
         [com.zyz.mybatis.mapper.TeacherMapper.getTeacher2]-<==      Total: 1
         TeacherT(id=1, name=玉小刚, studentTs=[
                                               StudentT(id=1, name=唐三, tid=1),
                                               StudentT(id=2, name=小舞, tid=1),
                                               StudentT(id=3, name=戴沐白, tid=1),
                                               StudentT(id=4, name=朱朱清, tid=1),
                                               StudentT(id=5, name=奥斯卡, tid=1),
                                               StudentT(id=6, name=宁荣荣, tid=1),
                                               StudentT(id=7, name=马红俊, tid=1),
                                               StudentT(id=8, name=白尘香, tid=1)
                                               ])
         [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@589b3632]
         *
         **/
    }

5、后语

项目源码位置:GitHub 传送门

在这里插入图片描述

项目结构如下:

在这里插入图片描述