第五天Mybatis总结——MyBatis的延迟加载+查询缓存

MyBatis的延迟加载
通过前面的技术点学习,可以知道通过resultMap元素可以实现mybatis的高级映射输出,association可以实现一对一高级映射,collection可以实现一对多高级映射,而association和collection还具有延迟加载的功能。
所谓的延迟加载就是先查询主表信息,主表信息查询完毕后,再按照主表相关数据完成关联表信息的查询,这就是延迟加载。即:在SQL查询中,先查询一部分(主表信息),再查询另一部分(关联表信息)。

具体列子
在实现查询订单表并关联查询用户表的SQL查询中,SQL语句书写形式如下:

select order.*,user.* form order,user where order.user_id = user.user_id
对上面的sql语句进行拆分:
1select * from orders
2select * from user where user_id=?

在mapper中组装SQL
将拆分的sql在mapper.xml中配置出来,并用resultMap元素完成组装

<resultMap type="delayedload.User" id="userMap">
        <id property="userId" column="user_id"/>
</resultMap>
<resultMap type="delayedload.Order" id="orderLazyLoadingMap">
        <id property="orderId" column="order_id"/>
        <!-- 延迟加载 -->
        <!-- property代表Order中的user属性   
             select代表延迟执行的sql
             column代表执行sql时的传参列
         -->
        <association property="user" javaType="delayedload.User" select="findUserByOrder" column="user_id">
        </association>
</resultMap>


<select id="findOrderLazyLoading" resultMap="orderLazyLoadingMap">
        select * from orders
</select>

<select id="findUserByOrder" resultMap="userMap">
        select * from user where user_id = #{user_id}
</select>

配置mybatis的延迟加载
在mybatis中默认是关闭延迟加载的,如果要实现延迟加载,需要在SqlMapConfig.xml全局配置文件中打开延迟加载,使用settings元素进行设置,更改如下:
这里写图片描述

<!-- 配置延迟加载 -->
<settings>
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="true"/>
</settings>

深入了解mybatis缓存
mybatis提供了查询缓存功能,用于减轻数据压力,提高数据库性能。mybatis提供了一级缓存和二级缓存,如下图所示:
这里写图片描述

从上图可以看出:
一级缓存是存在于一个sqlSession中的,而sqlSession就是操作数据库的一个会话对象,在对象中实际存储了一个hashMap的数据结构用于存储缓存数据。不同的sqlSession之间的缓存数据互不影响。
二级缓存是mapper级别的缓存,当多个sqlSession操作同一个mapper配置中的SQL语句时,多个sqlSession可以共用二级缓存,二级缓存是跨sqlSession的。
一级缓存:
mybatis一级缓存的作用域是同一个sqlSession,在同一个sqlSession中两次执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。当一个sqlSession结束后该sqlSession中的一级缓存也就不存在了。mybatis默认开启一级缓存。
如下图所示:
这里写图片描述

1.第一次执行查询id为1的用户的信息操作时,先在缓存中查找,如果没有,则执行数据库查询操作,并将从数据库中查询到的用户数据信息,并放入到一级缓存。
mybatis内部存储缓存使用一个HashMap,key为hashCode+sqlId+Sql语句。value为从查询出来映射生成的java对象

2.如果sqlSession执行insert、update、delete等操作commit提交后会清空一级缓存,这样做的目的是为了让缓存中存储的数据是最新的信息,避免脏读。

3.第二次执行查询id为1的用户的信息操作时,先去缓存中查找,如果缓存中有,则直接从缓存中获取用户信息。

注意:在正式开发中,是将mybatis和Spring进行整合开发,事务是在service层进行控制,一个service方法中包含很多mapper方法的调用。
在service方法开始执行时,就会开启事务,在开启事务的过程中就会创建SqlSession对象,因此期间不管是调用哪个mapper的方法,都是走一级缓存,有就从缓存中取,没有就从数据库中查询。方法结束时,事务关闭,同时清空一级缓存。
因此在同一service方法中是走一级缓存,如果是两次调用service方法,不走一级缓存,因为方法结束,SqlSession也就关闭,一级缓存就会被清空。

二级缓存:
在mybatis中允许多个SqlSession对象共享一个缓存区域,只不过这个缓存区域并一定在内存中,也可能是存储硬盘空间内,这个共享区域就是mybatis的二级缓存。mybatis同样适用hashMap这种数据结构来存储二级缓存中保存的数据。 如下图所示:
这里写图片描述

从上图中可以看出,mybatis的二级缓存是根据mapper配置文件的namespace命名空间进行划分的,相同namespace的查询数据操作放在同一个缓存区中。即用户的查询操作的数据是放在UserMapper的缓存区中,订单查询操作的数据是放在OrderMapper的缓存区中。
如果两个用户的SqlSession会话都是执行同一个UserMapper接口中的方法,并且都去查询用户数据,每次查询都会先从缓存区中查找,如果找不到从数据库中查询,查询到的数据写入到二级缓存。
任何一个用户的SqlSession 执行insert、update、delete等操作commit提交后都会清空该mapper下的二级缓存区域。

在mybatis中二级缓存是默认关闭的,如果要开启mybatis的二级缓存,配置如下:

1、在SqlMapConfig.xml全局配置文件中加入setting信息

<setting name="cacheEnabled" value="true"/>

2、在需要开启的二级缓存的mapper.xml中加入cache标签
只要加入cache标签就表示开启二级缓存

<cache />

二级缓存需要查询结果映射的pojo对象实现java.io.Serializable接口实现序列化和反序列化操作,注意如果存在父类、成员pojo都需要实现序列化接口。因为mybatis实现的二级缓存,数据并不一定存储在内存中,也有可能是其他位置,比如硬盘、网络空间等。

在SqlSession会话中,如果会话没有结束,数据只会存储于一级缓存中,如果此SqlSession的会话结束并且此命名空间的mapper开启了二级缓存,这时数据才会写入到二级缓存中。

猜你喜欢

转载自blog.csdn.net/qq_39411208/article/details/81458910
今日推荐