mybatis多对一和一对多查询数据处理解读

举报
yd_249383650 发表于 2023/07/30 17:05:48 2023/07/30
【摘要】 ​ 目录概述 准备工作 多对一问题的引出级联属性映射处理 association处理分步查询  一对多 问题的引出collection处理 分步查询 延迟加载解读什么是延迟加载?在mybatis中怎么开启延迟加载呢?概述 MyBatis 的一对多、多对一,主要就是 resultMapresultMapresultMap 两个属性的使用,而一对多和多对一都是相互的,只是站的角度不同:【一对多】...

 

目录


概述 

准备工作

 多对一

问题的引出

级联属性映射处理

 association处理

分步查询 

 一对多

 问题的引出

collection处理

 分步查询

 延迟加载解读

什么是延迟加载?

在mybatis中怎么开启延迟加载呢?



概述 

MyBatis 的一对多、多对一,主要就是 resultMapresultMapresultMap 两个属性的使用,而一对多和多对一都是相互的,只是站的角度不同:

  • 【一对多】association:一个复杂的类型关联。许多结果将包成这种类型
  • 【多对一】collection:复杂类型的集合

准备工作

由于本文是作为解读处理,在这里将不再赘述工程的搭建,只在这里只带大家过一下我们准备的实体类和pojo对象

准备的表有俩张,一个是学生表(t_student),一个是班级表(t_clazz)学生表可以通过cid字段到班级表中查询到对应的班级,java程序控制的外键,俩张表的数据如下:

编辑


编辑

 工程目录如下:

编辑


 多对一

问题的引出

假设我们要去查询一个学生的信息,这个信息包括班级信息,我们在mysql如何进行查询呢?大家很自然而然的就会想到通过多表联查即可即以下语句:

SELECT * FROM t_student 
LEFT JOIN t_clazz 
ON t_clazz.`cid`=t_student.`cid`
WHERE sid=1

 查询的结果如下:

编辑

 如果我们要将这条记录返回给mybatis进行的数据的封装,就需要提供一个实体类student,那么这个的时候我们需要对这个实体类的属性进行考虑,多个学生对应一个班级也就是多对一,我们把班级作为一个实体类,学生的属性中有班级这一个属性。

班级类(clazz)如下:

@Data
public class Clazz {
    private  Long cid;
    private  String cname;
}

学生类(student)如下:

@Data
public class Student {
    private  Long sid;
    private  String sname;
    private  Clazz clazz;
}

Clazz clazz; 表示学生关联的班级对象。 

级联属性映射处理

 StudentMapper接口中编写接口

    /**
     * 根据id查询学生信息
     * @param id
     * @return
     */
    Student selectById(@Param("id") Long id);

 StudentMapper.xml中实现

    <resultMap id="studentResultMap" type="com.study.pojo.Student">
        <id property="sid" column="sid"/>
        <result property="sname" column="sname"/>
        <result property="clazz.cid" column="cid"/>
        <result property="clazz.cname" column="cname"/>
    </resultMap>

    <select id="selectById" resultMap="studentResultMap">
        SELECT * FROM t_student
        LEFT JOIN t_clazz
        ON t_clazz.`cid`=t_student.`cid`
        WHERE sid=#{id}
    </select>

 级联属性映射,就是利用resultMap标签对属性和字段进行映射,内部对象的所属属性也进行映射,而SQL语句就进行表的连接进行查询。例如:clazz.cid

测试代码:

    @Test
    public void test01(){
        SqlSession session = SqlSessionUtil.openSession();
        StudentMapper mapper = session.getMapper(StudentMapper.class);
        Student student = mapper.selectById(1L);
        System.out.println(student);
    }

编辑

 association处理

association 翻译为关联的意思。它是resultMap 标签中的一个子标签。也是用来处理映射的,当一对象属性中存在另一个对象时,可以利用association 指明其对象中属性及其对应映射。

其他位置都不需要修改,只需要修改resultMap中的配置:association即可。

编辑

分步查询 

分步查询处理顾名思义将查询的步骤进行分步,在我们进行查询学生信息的时候,可以分为俩步

第一步先到学生表中查到学生的sid和sname,cid

第二步拿第一步中得到的cid去班级表中查询cname 

具体实施

第一处:association中select位置填写sqlId。sqlId=namespace+id。其中column属性作为这条子sql语句的条件。

    <resultMap id="studentResultMap" type="com.study.pojo.Student">
        <id property="sid" column="sid"/>
        <result property="sname" column="sname"/>
        <association property="clazz"
                     select="com.study.mapper.ClazzMapper.selectById"
                     column="cid"></association>
    </resultMap>

    <select id="selectById" resultMap="studentResultMap">
        SELECT * FROM t_student
        LEFT JOIN t_clazz
        ON t_clazz.`cid`=t_student.`cid`
        WHERE sid=#{id}
    </select>

第二处:在ClazzMapper接口中添加方法

   /**
     * 根据id查询班级信息
     * @param id
     */
    Clazz selectById(@Param("id") Long id);

第三处:在ClazzMapper.xml文件中进行配置

    <select id="selectById" resultType="com.study.pojo.Clazz">
        select  * from t_clazz where cid=#{id}
    </select>

逻辑如下: 

编辑

 执行结果,可以很明显看到先后有两条sql语句执行:

编辑


 一对多

 问题的引出

 假设我们要去查一个班级的信息,包括班级的名字,班号以及这个班级的的所有学生。这就是一对多,一个班级对应多个学生。这个需求的话我们在mysql中查询的语句如下:

SELECT * FROM  t_clazz 
LEFT JOIN t_student 
ON t_clazz.`cid`=t_student.`cid`
WHERE t_clazz.`cid`=2101

查询结果: 

编辑

 这个时候就要在Clazz类中添加List<Student> stus 属性。

@Data
public class Clazz {
    private  Long cid;
    private  String cname;
    List<Student> stus;
}

collection处理

 ClazzMappe编写r接口

    /**
     * 根据班级编号查询班级信息。同时班级中所有的学生信息也要查询。
     * @param cid
     * @return
     */
    Clazz selectClazzAndStusByCid(@Param("cid") Long cid);

ClazztMapper.xml中实现

  <resultMap id="clazzResultMap" type="com.study.pojo.Clazz">
        <id property="cid" column="cid"></id>
        <result property="cname" column="cname"></result>
        <collection property="stus" ofType="com.study.pojo.Student">
            <id property="sid" column="sid"></id>
            <result property="sname" column="sname"></result>
        </collection>
    </resultMap>
    <select id="selectClazzAndStusByCid" resultMap="clazzResultMap">
        SELECT * FROM  t_clazz
        LEFT JOIN t_student
        ON t_clazz.`cid`=t_student.`cid`
        WHERE t_clazz.`cid`=#{cid}
    </select>

测试代码

    @Test
    public void test01(){
        SqlSession session = SqlSessionUtil.openSession();
        ClazzMapper mapper = session.getMapper(ClazzMapper.class);
        Clazz clazz = mapper.selectClazzAndStusByCid(2101L);
        System.out.println(clazz);
    }

编辑

 分步查询

这个过程同样可以分为俩步:

第一步根据cid在班级表中查询cname

第二步根据cid在学生表中查询每个学生的sid sname 

具体实施

ClazzMapper.xml中修改

  <resultMap id="clazzResultMap" type="com.study.pojo.Clazz">
        <id property="cid" column="cid"></id>
        <result property="cname" column="cname"></result>
        <collection property="stus"
                    select="com.study.mapper.StudentMapper.selectByCid"
                    column="cid">
        </collection>
    </resultMap>

    <select id="selectClazzAndStusByCid" resultMap="clazzResultMap">
        select  * from t_clazz where cid=#{cid}
    </select>

StudentMapper接口

    /**
     * 根据班级编号获取所有的学生。
     * @param cid
     * @return
     */
    List<Student> selectByCid(@Param("cid") Long cid);

 StudentMapper.xml

    <select id="selectByCid" resultType="com.study.pojo.Student">
        select * from t_student where cid=#{cid}
    </select>

 编辑

 延迟加载解读

什么是延迟加载?

 ​ 延迟加载也称为懒加载、惰性加载,使用延迟加载可以提高程序的运行效率,针对数据持久层的操作,在某些特定查询的情况下去访问特定的数据库,在其他情况下可以不访问某些数据表,尽量减少 SQL 的执行,从而达到提高速度的目的,是对数据库操作的一种优化。

说明:延迟加载只存在于分步查询

在mybatis中怎么开启延迟加载呢?

局部开启: 

 在association或者collection标签中添加fetchType="lazy"。
    注意:默认是没有开启延迟加载的,而且这种在association或者collection中设置
    延迟加载的方式,是局部的设置,只针对当前association或者collection所关联的SQL语句起作用。

编辑

测试代码

    @Test
    public void test01(){
        SqlSession session = SqlSessionUtil.openSession();
        ClazzMapper mapper = session.getMapper(ClazzMapper.class);
        Clazz clazz = mapper.selectClazzAndStusByCid(2101L);
        //没有用到stus属性
        System.out.println(clazz.getCid());
        System.out.println(clazz.getCname());
    }

运行结果 

编辑

 我们可以很明显的看到延迟加载以后,只执行了一条sql语句

全局开启:

可以在mybatis核心配置文件中开启全局设置
 在开发中大部分情况是需要用到延迟加载的,所以建议开启全局的延迟加载机制
 在mybatis核心配置文件中添加<setting name="lazyLoadingEnabled" value="true"/> 

 实际中的开发模式:
    把全局延迟加载打开。
    如果某一步不需要延迟加载,设置fetchType="eager"。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。