首页 > 其他分享 >十三 MyBatis的高级映射及延迟加载

十三 MyBatis的高级映射及延迟加载

时间:2024-11-07 13:17:57浏览次数:3  
标签:sname 映射 cid Clazz mybatis student MyBatis public 加载

十三、MyBatis的高级映射及延迟加载

模块名:mybatis-009-advanced-mapping

打包方式:jar

依赖:mybatis依赖、mysql驱动依赖、junit依赖、logback依赖

配置文件:mybatis-config.xml、logback.xml、jdbc.properties

拷贝工具类:SqlSessionUtil

准备数据库表:一个班级对应多个学生。班级表:t_clazz。学生表:t_student

创建pojoStudentClazz

package com.study.mybatis.pojo;

/**
 * 学生类
 * @author sqnugy
 * @version 1.0
 * @since 1.0
 */
public class Student {
    private Integer sid;
    private String sname;
    //......
}

package com.study.mybatis.pojo;

/**
 * 班级类
 * @author sqnugy
 * @version 1.0
 * @since 1.0
 */
public class Clazz {
    private Integer cid;
    private String cname;
    //......
}

创建mapper接口:StudentMapperClazzMapper

创建mapper映射文件:StudentMapper.xmlClazzMapper.xml

13.1 多对一

多种方式,常见的包括三种:

  • 第一种方式:一条SQL语句,级联属性映射。
  • 第二种方式:一条SQL语句,association。
  • 第三种方式:两条SQL语句,分步查询。(这种方式常用:优点一是可复用。优点二是支持懒加载。)

第一种方式:级联属性映射

pojoStudent中添加一个属性:Clazz clazz; 表示学生关联的班级对象。

package com.study.mybatis.pojo;

/**
 * 学生类
 * @author sqnugy
 * @version 1.0
 * @since 1.0
 */
public class Student {
    private Integer sid;
    private String sname;
    private Clazz clazz;

    public Clazz getClazz() {
        return clazz;
    }

    public void setClazz(Clazz clazz) {
        this.clazz = clazz;
    }

    @Override
    public String toString() {
        return "Student{" +
                "sid=" + sid +
                ", sname='" + sname + '\'' +
                ", clazz=" + clazz +
                '}';
    }

    public Student() {
    }

    public Student(Integer sid, String sname) {
        this.sid = sid;
        this.sname = sname;
    }

    public Integer getSid() {
        return sid;
    }

    public void setSid(Integer sid) {
        this.sid = sid;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }
}

<?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">

<mapper namespace="com.study.mybatis.mapper.StudentMapper">

    <resultMap id="studentResultMap" type="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="selectBySid" resultMap="studentResultMap">
        select s.*, c.* from t_student s join t_clazz c on s.cid = c.cid where sid = #{sid}
    </select>

</mapper>
package com.study.mybatis.test;

import com.study.mybatis.mapper.StudentMapper;
import com.study.mybatis.pojo.Student;
import com.study.mybatis.utils.SqlSessionUtil;
import org.junit.Test;

public class StudentMapperTest {
    @Test
    public void testSelectBySid(){
        StudentMapper mapper = SqlSessionUtil.openSession().getMapper(StudentMapper.class);
        Student student = mapper.selectBySid(1);
        System.out.println(student);
    }
}

执行结果:

第二种方式:association

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

<resultMap id="studentResultMap" type="Student">
  <id property="sid" column="sid"/>
  <result property="sname" column="sname"/>
  <association property="clazz" javaType="Clazz">
    <id property="cid" column="cid"/>
    <result property="cname" column="cname"/>
  </association>
</resultMap>

association翻译为:关联。
学生对象关联一个班级对象。

第三种方式:分步查询

其他位置不需要修改,只需要修改以及添加以下三处:

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

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

<select id="selectBySid" resultMap="studentResultMap">
  select s.* from t_student s where sid = #{sid}
</select>

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

package com.study.mybatis.mapper;

import com.study.mybatis.pojo.Clazz;

/**
 * Clazz映射器接口
 * @author sqnugy
 * @version 1.0
 * @since 1.0
 */
public interface ClazzMapper {

    /**
     * 根据cid获取Clazz信息
     * @param cid
     * @return
     */
    Clazz selectByCid(Integer cid);
}

第三处:在ClazzMapper.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">

<mapper namespace="com.study.mybatis.mapper.ClazzMapper">
    <select id="selectByCid" resultType="Clazz">
        select * from t_clazz where cid = #{cid}
    </select>
</mapper>

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

分步优点:

  • 第一个优点:代码复用性增强。
  • 第二个优点:支持延迟加载。【暂时访问不到的数据可以先不查询。提高程序的执行效率。】

13.2 多对一延迟加载

要想支持延迟加载,非常简单,只需要在association标签中添加fetchType="lazy"即可。

修改StudentMapper.xml

文件:

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

我们现在只查询学生名字,修改测试程序:

public class StudentMapperTest {
    @Test
    public void testSelectBySid(){
        StudentMapper mapper = SqlSessionUtil.openSession().getMapper(StudentMapper.class);
        Student student = mapper.selectBySid(1);
        //System.out.println(student);
        // 只获取学生姓名
        String sname = student.getSname();
        System.out.println("学生姓名:" + sname);
    }
}

如果后续需要使用到学生所在班级的名称,这个时候才会执行关联的sql语句,修改测试程序:

public class StudentMapperTest {
    @Test
    public void testSelectBySid(){
        StudentMapper mapper = SqlSessionUtil.openSession().getMapper(StudentMapper.class);
        Student student = mapper.selectBySid(1);
        //System.out.println(student);
        // 只获取学生姓名
        String sname = student.getSname();
        System.out.println("学生姓名:" + sname);
        // 到这里之后,想获取班级名字了
        String cname = student.getClazz().getCname();
        System.out.println("学生的班级名称:" + cname);
    }
}

通过以上的执行结果可以看到,只有当使用到班级名称之后,才会执行关联的sql语句,这就是延迟加载。

在mybatis中如何开启全局的延迟加载呢?需要setting配置,如下:

<settings>
  <setting name="lazyLoadingEnabled" value="true"/>
</settings>

fetchType="lazy"去掉。

执行以下程序:

public class StudentMapperTest {
    @Test
    public void testSelectBySid(){
        StudentMapper mapper = SqlSessionUtil.openSession().getMapper(StudentMapper.class);
        Student student = mapper.selectBySid(1);
        //System.out.println(student);
        // 只获取学生姓名
        String sname = student.getSname();
        System.out.println("学生姓名:" + sname);
        // 到这里之后,想获取班级名字了
        String cname = student.getClazz().getCname();
        System.out.println("学生的班级名称:" + cname);
    }
}

通过以上的测试可以看出,我们已经开启了全局延迟加载策略。

开启全局延迟加载之后,所有的sql都会支持延迟加载,如果某个sql你不希望它支持延迟加载怎么办呢?将fetchType设置为eager:

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

这样的话,针对某个特定的sql,你就关闭了延迟加载机制。

后期我们要不要开启延迟加载机制,主要看实际的业务需求是怎样的。

13.3 一对多

一对多的实现,通常是在一的一方中有List集合属性。

在Clazz类中添加List<Student> stus; 属性。

public class Clazz {
    private Integer cid;
    private String cname;
    private List<Student> stus;
    // set get方法
    // 构造方法
    // toString方法
}

一对多的实现通常包括两种实现方式:

  • 第一种方式:collection
  • 第二种方式:分步查询

第一种方式:collection

package com.study.mybatis.mapper;

import com.study.mybatis.pojo.Clazz;

/**
 * Clazz映射器接口
 * @author sqnugy
 * @version 1.0
 * @since 1.0
 */
public interface ClazzMapper {

    /**
     * 根据cid获取Clazz信息
     * @param cid
     * @return
     */
    Clazz selectByCid(Integer cid);

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

<resultMap id="clazzResultMap" type="Clazz">
  <id property="cid" column="cid"/>
  <result property="cname" column="cname"/>
  <collection property="stus" ofType="Student">
    <id property="sid" column="sid"/>
    <result property="sname" column="sname"/>
  </collection>
</resultMap>

<select id="selectClazzAndStusByCid" resultMap="clazzResultMap">
  select * from t_clazz c join t_student s on c.cid = s.cid where c.cid = #{cid}
</select>

注意是ofType,表示“集合中的类型”。

package com.study.mybatis.test;

import com.study.mybatis.mapper.ClazzMapper;
import com.study.mybatis.pojo.Clazz;
import com.study.mybatis.utils.SqlSessionUtil;
import org.junit.Test;

public class ClazzMapperTest {
    @Test
    public void testSelectClazzAndStusByCid() {
        ClazzMapper mapper = SqlSessionUtil.openSession().getMapper(ClazzMapper.class);
        Clazz clazz = mapper.selectClazzAndStusByCid(1001);
        System.out.println(clazz);
    }
}

执行结果:

第二种方式:分步查询

修改以下三个位置即可:

<resultMap id="clazzResultMap" type="Clazz">
  <id property="cid" column="cid"/>
  <result property="cname" column="cname"/>
  <!--主要看这里-->
  <collection property="stus"
              select="com.study.mybatis.mapper.StudentMapper.selectByCid"
              column="cid"/>
</resultMap>

<!--sql语句也变化了-->
<select id="selectClazzAndStusByCid" resultMap="clazzResultMap">
  select * from t_clazz c where c.cid = #{cid}
</select>
/**
* 根据班级编号获取所有的学生。
* @param cid
* @return
*/
List<Student> selectByCid(Integer cid);
<select id="selectByCid" resultType="Student">
  select * from t_student where cid = #{cid}
</select>

执行结果:

13.4 一对多延迟加载

一对多延迟加载机制和多对一是一样的。同样是通过两种方式:

  • 第一种:fetchType=“lazy”
  • 第二种:修改全局的配置setting,**lazyLoadingEnabled=true,**如果开启全局延迟加载,想让某个sql不使用延迟加载:fetchType="eager"

标签:sname,映射,cid,Clazz,mybatis,student,MyBatis,public,加载
From: https://blog.csdn.net/wgy17734894660/article/details/143572741

相关文章

  • 如何看懂sa-token 第一篇 是怎么设计被spring加载的
    2023年入职了一家公司,他们给到我这边的系统架构我看基本都用到了sa-token,抱着去学习的态度去官网看了文档Sa-Token,感觉有些头大,摸不着头脑,然后尝试去下载源码来看gitclonehttps://gitee.com/dromara/sa-token.git我看的时候,最新版本是v1.39.0,代码一大推,实在看不明白看懂源......
  • 3D高斯的内存数据加载节省问题
      1加载数据readColmapSceneInfo 读取全部原图  3对原图是否缩放 如果缩放缩放后的原图当真图 因此内存占用的足够大,因为所有数据提前加载到内存里。解决1大力出奇迹,开启共享内存,增大硬件内存2分批次加载,只有在训练用到这张图时候,才临时加载这张图......
  • oracle11g启动过程中加载配置文件
    oracle指定配置文件启动,要是不指定配置文件启动的话默认找的参数文件顺序如下:在oracle11g中oracle启动过程中默认会加载相应的配置文件来启动oracle服务。检查参数文件有两个,一个是spfile<ORACLE_SID>.ora文件,另一个是inti<ORACLE_SID>.ora文件。oracle软件服务安装完成后......
  • java的类加载机制详解
    Java的类加载机制是一个复杂但非常重要的过程,因为它决定了程序如何找到并加载类文件。下面我会逐步详细讲解整个机制。1.什么是类加载机制?简单来说,类加载机制就是Java虚拟机(JVM)在运行时将.class文件中的字节码加载到内存中并进行解析的过程。这个机制让JVM可以动态加......
  • 前端开发中如何在页面加载时自动读取并转换指定的 .docx 文件
    前端开发中如何在页面加载时自动读取并转换指定的.docx文件,并实现在线预览功能。我在这里分享通过mammoth.min.js插件来实现docx在线预览功能第1:下载地址,大家可以任意选取下面其中一种方式下载(1)GitHub-mwilliamson/mammoth.js:ConvertWorddocuments(.docxfiles)toH......
  • 在 Windows Server 2025 中,WebDAV 重定向程序(WebDAV Redirector)是一个客户端组件,用于
    在WindowsServer2025和更高版本中,WebDAV(Web-basedDistributedAuthoringandVersioning)协议仍然可以通过启用IIS(InternetInformationServices)角色来使用。你可以安装并配置IIS中的WebDAV模块来实现文件共享和远程访问。在WindowsServer2025中,WebDAV重定向程序......
  • Mybatis-Plus 的修改策略
    Mybatis-Plus的修改策略Mybatis-Plusupdatestrategy使用Mybatis-Plus提供的更新方法时,若实体中的字段为null,默认情况下,最终生成的update语句中,不会包含该字段。但是如果为空串时还是会操作.若想改变默认行为,可做以下配置。全局配置在application.yml中配置如下参数mybat......
  • MyBatis 动态 SQL 详解
    动态SQL简介动态SQL是MyBatis的强大特性之一,它允许在XML映射文件内以标签的形式编写动态SQL,完成逻辑判断和动态拼接SQL的功能。动态SQL可以根据用户输入或外部条件动态地构建查询,避免了硬编码查询逻辑,简化了数据库查询的复杂度,同时提高了代码的可读性和维护性。......
  • 一起单测引起的项目加载失败惨案
    作者:京东科技宋慧超一、前言最近在开发一个功能模块时,在功能自测阶段,通过使用单测测试功能的完整性,在测试单测联通性使用到静态方法测试时,发现单测报错,通过查阅解决方案发现需要对Javaassist包进行排包或者升版本处理。通过排包解决掉单测报错,在部署项目时发现频繁报bean注入......
  • MyBatis实现原理
    MyBatis底层实现原理1、MyBatis实现基础1.1、动态代理1.2、责任链1.3、动态代理和责任链结合使用实例1.3.1定义接口1.3.2.实现接口1.3.3创建InvocationHandler1.3.4使用动态代理和责任链2、MyBatis底层原理2.1拦截器接口Interceptor2.2插件Plugin2.3执行引擎Ex......