Mybatis 延迟加载和缓存

一、延迟加载简介

(1)概念:

延迟加载,也称为懒加载(LazyLoding)。

当代码中执行到查询语句时,并不是直接到DB中执行select语句进行查询,而是在需要它的时候才加载,不需要的话就不加载。

其实简单来说Mybatis的延迟加载就是分多次执行SQL语句,这样就实现了延迟加载的机制,并且第一次执行的结果值可能是接下来执行的SQL语句的参数值,Mybatis实现执行接下来的SQL的原理机制是通过代理类来实现的,就是第一次执行的结果对象其实已经是一个代理对象,当执行接下来相关的对象时会执行其他SQL语句,这样就实现了延迟加载的机制。

(2)延迟加载优点

懒加载主要是为了提高效率。假如说有一张用户表,还有一张聊天记录表。一个用户可能关联了 1000 条聊天记录。如果关联查询一次性就把这 1000 条数据查出来了,但是查出来这 1000 条数据,可能并没有用到聊天记录数据,只用到用户信息数据。懒加载的目的就是在用户真正需要查询数据的时候才去查询数据库,而不是第一次查询就查询出来。

(3)MyBatis的延迟加载

resultMap中的association和collection标签具有延迟加载的功能。

         1)只能对关联对象进行查询时,使用延迟加载策略。对于主加载对象,均采用直接加载。

         2)要应用延迟加载查询,只能使用多表单独查询,而不能使用多表连接查询。因为多表连接查询的本质是查询一张表,将多张表首先连接为了一张表后,再进行的查询。 查询一个信息,就会将所有信息全部查询到。

二、Mybatis延迟加载使用

(1)将mybaits配置文件的延迟加载开关打开,具体是在<settings>标签配置

      <!-- 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载 -->
        <setting name="lazyLoadingEnabled" value="true" /><!--默认为true-->
        <!-- true为全部加载,false为按需要加载(懒加载) -->
        <setting name="aggressiveLazyLoading" value="false" />

(2)配置映射文件

业务需求是:输入班级id查询班级信息,懒加载该班级所有学生的信息

 <!--配置延迟加载-->
  <select id="selectClassById" resultMap="ClassesResultMap" parameterType="Integer">
    select cid,className from classes where cid=#{cid}
  </select>
  <resultMap id="ClassesResultMap" type="Classes">
    <id column="cid" property="cid"/>
    <result column="className" property="className"/>
    <collection property="studentSet" column="cid" select="selectStudentById" fetchType="lazy">
      <result column="name" property="name"/>
    </collection>
  </resultMap>
  <select id="selectStudentById" resultType="Student" parameterType="Integer">
    select name from student where classId = #{cid}  <!--cid根据上面查询的结果-->
  </select>

测试结果:

说明:

  1. 一对一延迟加载时,把collection 换成association即可
  2. 延迟加载不能用表连接进行查询
  3. select:指定关联的查询语句
  4. collection 标签里的column:指定主语句中的哪个字段的值作为参数传递给从sql语句,通常为数据库表的外键值
  5. fetchType设置是否懒加载,lazy代表懒加载

注意:

1. lazyLoadingEnabled与aggressiveLazyLoading必须全部设置,且lazyLoadingEnabled为true,aggressiveLazyLoading为false才能让延迟加载真正生效

2.  toString与重载方法过滤:

     通常我们在测试时会在实体类加入toString,或者存在了一些重载方法,这些MyBatis会对其进行过滤,但是过滤会调     用cglib与asm指定包,因此要将两个包添加到buildpath。以下为两个包的maven依赖:

         <dependency>
	    	<groupId>cglib</groupId>
		<artifactId>cglib</artifactId>
		<version>3.1</version>
	 </dependency>
 
        <dependency>
            <groupId>asm</groupId>
            <artifactId>asm</artifactId>
            <version>3.3.1</version>
        </dependency>

 三、缓存

客户端向数据库服务器发送同样的sql查询语句,如果每次都去访问数据库,会导致性能的降低,这是就用到了缓存。

(1)一级缓存

Mybatis的一级缓存是指SqlSession。一级缓存的作用域是一个SqlSession。Mybatis默认开启一级缓存

在同一个SqlSession中,执行相同的查询SQL,第一次会去查询数据库,并写到缓存中;第二次直接从缓存中取。

SqlSession的缓存清空三种方式:

  1. 当执行SQL时两次查询中间发生了增删改操作
  2. session.commit()
  3. session.clearCache()

例子:执行两次查询,发现只执行一次select语句,执行session.clearCache()语句,清空缓存,则会执行两次select语句

(2)二级缓存

二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace,不同的sqlSession两次执行相同 namespace下的sql语句且向sql中传递参数也相同即最终执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二 次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。Mybatis默认是没有开启二级缓存

说明:

第一次调用mapper下的SQL去查询用户信息。查询到的信息会存到该mapper对应的二级缓存区域内。

第二次调用相同namespace下的mapper映射文件中相同的SQL去查询用户信息。会去对应的二级缓存内取结果。

如果调用相同namespace下的mapper映射文件中的增删改SQL,并执行了commit操作。此时会清空该namespace下的二级缓存。

应用场景:

对于访问多的查询请求且用户对查询结果实时性要求不高的,可以使用mybatis的二级缓存,降低数据库访问量,提高访问速度,例如:耗时较高的统计分析sql,电话账单查询,前一个月的消费查询等。 

使用二级缓存 

(1)setting全局参数设置

<!-- 这个配置使全局的映射器启用或禁用缓存 -->
        <setting name="cacheEnabled" value="true" />

(2)配置sql映射文件

表示把此SQL映射文件的mapper对象的二级缓存功能打开

<cache/>

​ 如果这样配置的话,很多其他的配置就会被默认进行,如:

  • 映射文件所有的select 语句会被缓存
  • 映射文件的所有的insert、update和delete语句会刷新缓存
  • 缓存会使用默认的Least Recently Used(LRU,最近最少使用原则)的算法来回收缓存空间
  • 根据时间表,比如No Flush Interval,(CNFI,没有刷新间隔),缓存不会以任何时间顺序来刷新
  • 缓存会存储列表集合或对象(无论查询方法返回什么)的1024个引用
  • 缓存会被视为是read/write(可读/可写)的缓存,意味着对象检索不是共享的,而且可以很安全的被调用者修改,不干扰其他调用者或县城所作的潜在修改

手动配置:

<cache eviction="LRU" flushInterval="100000" size="1024" readOnly="true"/>

各个属性意义如下:

  • eviction:缓存回收策略
    - LRU:最少使用原则,移除最长时间不使用的对象
    - FIFO:先进先出原则,按照对象进入缓存顺序进行回收
    - SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象
    - WEAK:弱引用,更积极的移除移除基于垃圾回收器状态和弱引用规则的对象
  • flushInterval:刷新时间间隔,单位为毫秒,这里配置的100毫秒。如果不配置,那么只有在进行数据库修改操作才会被动刷新缓存区
  • size:引用额数目,代表缓存最多可以存储的对象个数
  • readOnly:是否只读,如果为true,则所有相同的sql语句返回的是同一个对象(有助于提高性能,但并发操作同一条数据时,可能不安全),如果设置为false,则相同的sql,后面访问的是cache的clone副本。

(3)实现序列化

由于二级缓存的数据不一定都是存储到内存中,它的存储介质多种多样,所以需要给缓存的对象执行序列化。

如果该类存在父类,那么父类也要实现序列化。

禁用二级缓存

<select>标签设置 useCache="false"

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值