0.什么是N+1问题?

在查询中一下子取出所有属性,就会使数据库多执行几条毫无意义的SQL 。
实际中不需要把所有信息都加载进来,因为有些信息并不常用,加载它们会多执行几条毫无用处的 SQL,导致数据库资源的损耗和系统性能的下降。
假设现在有 N 个关联关系完成了级联,那么只要再加入一个关联关系,就变成了 N+l个级联,所有的级联 SQL 都会被执行,显然会有很多并不是我们关心的数据被取出,这样会造成很大的资源浪费,这就是 N+l 问题,尤其是在那些需要高性能的互联网系统中,这往往是不被允许的。
为了应对 N+l 问题, MyBatis 提供了延迟加载功能。

1.什么是延迟加载

MyBatis 支持延迟加载,把常用的级联数据通过 SQL 直接查询出来,而对于那些不常用的级联数据不要取出,而是等待要用时才取出,这些不常用的级联数据可以采用了延迟加载的功能

resultMap可以实现高级映射(使用association、collection实现一对一及一对多映射),association、collection具备延迟加载功能。

需求:

如果查询订单并且关联查询用户信息。如果先查询订单信息即可满足要求,当我们需要查询用户信息时再查下用户信息。把对用户信息的按需去查询就是延迟加载。

延迟加载:先从单表查询、需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。

2.使用association实现延迟加载

2.1需求

查询订单并且关联查询用户信息

2.2mapper.xml

需要定义两个mapper的方法对应的statement。

(1)只查询订单信息

SELECT * FROM orders

在查询订单的statement中使用association去延迟加载(执行)下边的statement(关联查询用户信息)。

    <!-- 查询订单关联查询用户  -->
<select id="findOrdersUserLazyLoading" resultMap="OrdersUserLazyLoadingResultMap">
SELECT * FROM orders
</select>

(2)关联查询用户信息

通过上边查询到的订单信息中user_id去关联查询用户信息

使用UserMapper.xml中的findUserById

    <select id="findUserById" parameterType="int" resultType="user">
select * from user where id=#{value}
</select>

上边先去执行findOrdersUserLazyLoading,当需要去查询用户的时候再去执行fingUserById,通过resultMap的定义将延迟加载执行配置起来。

2.3 延迟加载resultMap

使用association中的select指定延迟加载去执行的statement的id。

    <!-- 延迟加载的resultMap  -->
<resultMap type="joanna.yan.mybatis.entity.Orders" id="OrdersUserLazyLoadingResultMap">
<!-- 1.对订单信息进行映射配置 -->
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<result column="createtime" property="createtime"/>
<result column="note" property="note"/>
<!-- 2.实现对用户信息进行延迟加载 -->
<!-- select:指定延迟加载需要执行的statement的id(是根据user_id查询用户信息的statement)
要使用UserMapper.xml中findUserById完成根据用户id(user_id)用户信息的查询,
如果findUserById不在本mapper中需要前边加namespace。
column:订单信息中关联用户信息查询的列,是user_id
关联查询的sql理解为:
SELECT orders.*,
(SELECT username FROM USER WHERE orders.user_id = user.id)username,
(SELECT sex FROM USER WHERE orders.user_id = user.id)sex
FROM orders
-->
<association property="user" javaType="joanna.yan.mybatis.entity.User"
select="joanna.yan.mybatis.mapper.UserMapper.findUserById" column="user_id">
</association>
</resultMap>

2.4mapper.java

    //查询订单关联查询用户,用户信息时延迟加载
public List<Orders> findOrdersUserLazyLoading() throws Exception;

2.5测试

2.5.1测试思路

(1)执行上边mapper方法(findOrdersUserLazyLoading),内部去调用joanna.yan.mybatis.mapper.OrdersCustomMapper中findOrdersUserLazyLoading只查询orders信息(单表)。

(2)在程序中去遍历上一步骤查询出的List<Orders>,当我们调用Orders中的getUser()时,开始进行延迟加载。

(3)延迟加载,去调用UserMapper.xml中findUserById这个方法获取用户信息。

2.5.2延迟加载配置

mybatis默认没有开启延迟加载,需要在SqlMapConfig.xml中setting配置。

在mybatis核心配置文件中配置:

lazyLoadingEnabled、aggressiveLazyLoading

设置项

描述

允许值

默认值

lazyLoadingEnabled

全局性设置懒加载。如果设为‘false’,则所有相关联的都会被初始化加载。

true | false

false

aggressiveLazyLoading

当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载。

true | false

true

在SqlMapConfig.xml中配置:

     <!-- 全局配置参数,需要时再设置  -->
<settings>
<!-- 打开延迟加载的开关 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 将积极加载改为消极加载即按需要加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>

2.5.3测试代码

    @Test
public void findOrdersUserLazyLoadingTest() throws Exception{
SqlSession sqlSession=sqlSessionFactory.openSession();
OrdersCustomMapper ordersCustomMapper=sqlSession.getMapper(OrdersCustomMapper.class);
List<Orders> list=ordersCustomMapper.findOrdersUserLazyLoading();
for (Orders orders : list) {
//执行getUser()去查询用户信息,这里实现按需加载
User user=orders.getUser();
System.out.println(user);
}
sqlSession.close();
}

2.6延迟加载思考

不使用mybatis提供的association及collection中的延迟加载功能,如何实现延迟加载?

实现方法如下:

定义两个mapper方法:

(1)查询订单列表

(2)根据用户id查询用户信息

    实现思路:先去查询第一个mapper方法,获取订单信息列表

在测试程序中,按需去调用第二个mapper方法去查询用户信息。

总之,使用延迟加载方法,先去查询简单的sql(最好单表,也可以关联查询),再去按需要加载关联查询的其它信息。

原文地址:http://www.cnblogs.com/Joanna-Yan/p/6953005.html

Mybatis中的N+1问题与延迟加载的更多相关文章

  1. Mybatis中的延迟加载的使用方法

    Mybatis中的延迟加载的使用方法 在Mybatis中查询订单,然后带出商品信息和快递信息的配置方法 orderMapper.xml配置如下 <?xml version="1.0&q ...

  2. 【MyBatis学习11】MyBatis中的延迟加载

    1. 什么是延迟加载 举个例子:如果查询订单并且关联查询用户信息.如果先查询订单信息即可满足要求,当我们需要查询用户信息时再查询用户信息.把对用户信息的按需去查询就是延迟加载. 所以延迟加载即先从单表 ...

  3. 【mybatis深度历险系列】mybatis中的高级映射一对一、一对多、多对多

    学习hibernate的时候,小编已经接触多各种映射,mybatis中映射有到底是如何运转的,今天这篇博文,小编主要来简单的介绍一下mybatis中的高级映射,包括一对一.一对多.多对多,希望多有需要 ...

  4. SSM-MyBatis-18:Mybatis中二级缓存和第三方Ehcache配置

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 二级缓存 Mybatis中,默认二级缓存是开启的.可以关闭. 一级缓存开启的.可以被卸载吗?不可以的.一级缓存 ...

  5. mybatis中resultMap配置细则

    resultMap算是mybatis映射器中最复杂的一个节点了,能够配置的属性较多,我们在mybatis映射器配置细则这篇博客中已经简单介绍过resultMap的配置了,当时我们介绍了resultMa ...

  6. Mybatis 中延时加载

    1 为了处理N+1 问题,Mybatis 引入了延时加载功能,意义是一开始并不取出关联数据,只有当使用时,才发送sql语句去取. mybatis中两个全局设置 lazyLoadingEnabled 和 ...

  7. mybatis中的懒加载

    知识点:mybatis中的懒加载的使用 参考:https://www.cnblogs.com/ysocean/p/7336945.html?utm_source=debugrun&utm_me ...

  8. JDK、Spring和Mybatis中使用到的设计模式

    一.JDK中的设计模式 (1)结构性模式 1.适配器模式 java.util.Arrays#asList() java.io.InputStreamReader(InputStream) java.i ...

  9. Mybatis中使用collection进行多对多双向关联示例(含XML版与注解版)

    Mybatis中使用collection进行多对多双向关联示例(含XML版与注解版) XML版本: 实体类: @Data @NoArgsConstructor public class Course ...

随机推荐

  1. web中显示中文名称的图片,可以这样配置filter

    com.cy.filter.UrlFilter: package com.cy.filter; import java.io.IOException; import java.net.URLDecod ...

  2. linux 下安装doker centeros6.5

    通过 cat /proc/version .uname [root@192.168.1.1 ~]# cat /proc/version Linux version 2.6.32-279.el6.x86 ...

  3. Linux故障-bash-4.1$

    #模拟故障:-bash-4.1$ [root@nodchen ~]# su - cisco[cisco@nodchen ~]$ \rm -f .*rm: cannot remove `.': Is a ...

  4. oracle11g的dmp文件导入oracle10g时报错:头部验证失败

    因为本机安装的10g版本的Oracle,需要导入一个11g版本导出的dmp文件,Oracle数据库版本之间存在兼容的问题,低版本的库不能导入高版本的dmp文件,在CMD中导入dmp文件总是出现如下错误 ...

  5. Delphi Webbrowser使用方法详解(一)

    1.webbroser介绍 该组件是一个浏览器组件,可以显示一个指定地址的网页.设置网页打开时的主页以及对网页进行相关的操作,同时也可以对HTML文件进行剪切.复制.粘贴.删除等操作.该 组件在Int ...

  6. Hive基础之Hive表常用操作

    本案例使用的数据均来源于Oracle自带的emp和dept表 创建表 语法: CREATE [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name ...

  7. jmeter-noguimodel

    jmeter -Dthreads= -n -t ~/Desktop/image-controller.jmx -l myimage/out -e -o myimage/log -j myimage/r ...

  8. Django静态图片参数解析

    使用Django静态设置时,遇到很多问题,经过艰苦的Baidu, stack overflow, Django原档阅读,终于把静态图片给搞出来了.特记录下来. 关键的概念:Django中,静态资源的存 ...

  9. 20.Scrapy日常练手

    1.创建爬虫项目: scrapy  startproject tutorial 2.创建 spider cd tutorial scrapy  genspider quotes quotes.tosc ...

  10. php中点击链接直接下载图片

    最近需要一个功能,是点击链接,直接把图片下载下来,一般情况下,图片是在新页直接打开的,不会自动提示下载,在网上找来找,用这个挺好使,代码如下: $filename = basename($downfi ...