Mybatis关联(嵌套)查询与延迟加载

2022-12-02 10:51:27 浏览数 (1)

我们在查询业务数据的时候经常会遇到关联查询的情况,比如查询员工就会关联部门(一对一),查询学生成绩就会关联课程(一对一),查询订单就会关联商品(一对多),等等。

映射结果有两个标签,一个是,一个是。 是select标签的一个属性,适用于返回JDK类型(比如Integer. String等等)和实体类。这种情况下结果集的列和实体类的属性可以直接映射。如果返回的字段无法直接映射,就要用来建立映射关系。 对于关联查询的这种情况,通常不能用来映射。用映射,要么就是修改dto (Data Transfer Object),在里面增加字段,这个会导致增加很多无关的字段。要么就是引用关联的对象,比如Blog里面包含了一个Author对象(多对一),这种情况下就要用到关联查询(association,或者嵌套查询),MyBatis 可以帮我们自动做结果的映射。

association和collection的区别: association是用于一对一和多对一,而collection是用于一对多的关系。 一对一的关联查询有两种配置方式:

嵌套结果

代码语言:javascript复制
    <!-- 根据文章查询作者,一对一查询的结果,嵌套查询 -->
    <resultMap id="BlogWithAuthorResultMap" type="com.gupaoedu.domain.associate.BlogAndAuthor">
        <id column="bid" property="bid" jdbcType="INTEGER"/>
        <result column="name" property="name" jdbcType="VARCHAR"/>
        <!-- 联合查询,将author的属性映射到ResultMap -->
        <association property="author" javaType="com.gupaoedu.domain.Author">
            <id column="author_id" property="authorId"/>
            <result column="author_name" property="authorName"/>
        </association>
    </resultMap>

嵌套查询

代码语言:javascript复制
    <!-- 另一种联合查询(一对一)的实现,但是这种方式有“N 1”的问题 -->
    <resultMap id="BlogWithAuthorQueryMap" type="com.gupaoedu.domain.associate.BlogAndAuthor">
        <id column="bid" property="bid" jdbcType="INTEGER"/>
        <result column="name" property="name" jdbcType="VARCHAR"/>
        <association property="author" javaType="com.gupaoedu.domain.Author"
                     column="author_id" select="selectAuthor"/> <!-- selectAuthor 定义在下面-->
    </resultMap>

    <!-- 嵌套查询 -->
    <select id="selectAuthor" parameterType="int" resultType="com.gupaoedu.domain.Author">
        select author_id authorId, author_name authorName
        from author where author_id = #{authorId}
    </select>

其中第二种方式:嵌套查询,由于是分两次查询,当我们查询了Blog 信息之后,会再发送一条SQL到数据库查询部门信息。

我们只执行了一次查询Blog信息的SQL(所谓的1),如果返回了N条记录(比如10条Blog),因为一个Blog就有至少一个Author,就会再发送N条到数据库查询Author信息(所谓的N),这个就是我们所说的N 1的问题。这样会白白地浪费我们的应用和数据库的性能。 如果我们用了嵌套查询的方式,怎么解决这个问题?能不能等到使用Author 信息的时候再去查询?这个就是我们所说的延迟加载,或者叫懒加载。 在MyBatis里面可以通过开启延迟加载的开关来解决这个问题。

延迟加载

在settings标签里面可以配置:

代码语言:javascript复制
        <!-- 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。默认 false  -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- 当开启时,任何方法的调用都会加载该对象的所有属性。默认 false,可通过select标签的 fetchType来覆盖-->
        <setting name="aggressiveLazyLoading" value="true"/>
        <!--  Mybatis 创建具有延迟加载能力的对象所用到的代理工具,默认JAVASSIST -->
        <setting name="proxyFactory" value="CGLIB" />

lazyLoadingEnabled决定了是否延迟加载(默认false)。 aggressiveLazyLoading决定了是不是对象的所有方法都会触发查询。

0 人点赞