美文网首页
mybatis----缓存

mybatis----缓存

作者: n油炸小朋友 | 来源:发表于2018-09-15 18:36 被阅读0次

    查询缓存

    mybaits提供了一级缓存和二级缓存,用于减轻数据压力,提高数据库性能。。

    1.1 什么是一级缓存

    我们创建出一个SqlSession对象表示一次数据库会话,在这次会话中,我们有可能好几次执行一样的查询语句,若是每次都去访问数据库,那么就会造成数据库资源的浪费,所以mybatis引入一级缓存,在SqlSession中建立一个缓存(数据结构为hashmap),每次查询先去查看缓存中是否有,有的话就把结果返回,没有的话再去查询数据库并将查到的结果缓存起来。

    需要注意的是,不同的sqlSession对象之间的缓存数据区域是互相不影响的。

    SqlSession只是对外的接口,真正执行各种数据库操作的是Executor执行器(也是一个接口)。当创建了一个SqlSession对象时,MyBatis会为这个SqlSession对象创建一个新的Executor执行器,而缓存信息就被维护在这个Executor执行器中。MyBatis将缓存和对缓存相关的操作封装成了Cache接口中。
    SqlSession、Executor、Cache之间的关系如下列类图所示:


    sqlSession级别的一级缓存实际上就是使用PerpetualCache维护的。

    1.2一级缓存的生命周期

    1. 开启一个数据库会话时,会创建一个新的SqlSession对象,SqlSession对象中会有一个新的Executor对象,Executor对象中持有一个新的PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉;

    2. 如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,此时一级缓存不可用;

    3. 如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是PerpetualCache对象仍可使用;

    4.SqlSession中执行了一个更新增加删除操作 ,都会清空全部PerpetualCache对象的数据,但是该对象可以继续使用;

    1.3 一级缓存的工作流程

    1. 对于某个查询,根据statementId,params,rowBounds来构建一个key值;

    2. 根据这个key值去缓存Cache中判断是否命中缓存;

    3. 如果命中,则直接将缓存结果返回;

    4. 如果没命中:

       4.1  去数据库中查询数据,得到查询结果;
      
       4.2  将key和查询到的结果分别作为key,value对存储到Cache中;
      
       4.3. 将查询结果返回;
      
    5. 结束。

    1.4 如何判断两次查询是一样的

    从实现来看,mybatis是利用key是否相同来判断两次查询是否相同的,而key是由statementId,params,rowBounds这三项构建的。

    其中,statementId决定带参数的sql(有“?”占位符的的sql或是需要拼接字符串的sql语句),params决定占位符传入的参数或是要拼接的字符串,rowBounds决定查询的结果集的范围(也就是 limit x,y ),这三个参数决定了最终的sql,也就是说当这个最终的sql一样时,那么就判断这两次是一样查询。

    1.5 真正应用

    真正开发的时候,sqlSession是用spring管理的,而mapper是在service里面调用,在这种情况下,什么时候会用到一级缓存呢?
    实际上,在一个service里,只有一个sqlSession,在service结束之后才会关闭这个sqlSession,sqlSession关闭则缓存清空。所以一个service函数里面多次调用mapper是会走一级缓存的,而多次调用service则互不影响。


    2.1 什么是二级缓存

    二级缓存是namespace级别的缓存,多个SqlSession可以共用二级缓存,不同sqlSession操作同一个namespace下的同一个sql,就会走二级缓存。


    二级缓存工作流程

    2.2开启二级缓存

    在SqlMapConfig.xml里开启mybatis的全局二级缓存开关,默认是开启的:

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

    还需要在要二级缓存开启的mapper.xml里面开启开关:
    <cache/>

    2.3 二级缓存与一级缓存区别

    二级缓存与一级缓存区别,二级缓存的范围更大,多个sqlSession可以共享一个namespace下的二级缓存区域。

    2.4 测试二级缓存

    需要关闭sqlSession1才会把内容写到缓存,sqlSession2才会读到:


    在sqlSession1和sqlSession2之间加入以下代码,为了测试更新操作是否清空缓存:


    2.5 二级缓存参数设置

    设置某些sql禁用二级缓存

    在statement中设置useCache=false可以禁用当前select语句使用二级缓存,即每次查询都会发出sql去查询数据库。默认情况是true,即该sql使用二级缓存。

    <select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">

    只有每次查询都需要最新的数据sql,要设置成useCache=false,才禁用二级缓存。

    刷新缓存操作

    刷新就是清空缓存,在insert update delete等statement中设置flushCache="true"(默认就是true),进行这些操作后会清空缓存,可以避免脏读的情况。

    刷新间隔参数

    默认是没有刷新间隔,刷新只在调用语句时刷新(这里的刷新都是指清空)

    引用数目属性

    size:可被设置成任意正整数,默认值是1024

    readOnly属性

    可被设置成true或是false,默认是false。只读为true的缓存的对象实例是同一个;只读为false的缓存返回的对象实例是拷贝的(通过序列化,所以配置成false需要pojo实现序列化接口),慢但是安全。

    一个设置参数的例子

    <cache eviction="FIFO" flushInterval="60 000" size="512" readOnly="true"/>
    这个配置了一个FIFO缓存;并每隔60秒(60 000ms)刷新;存储结果对象或结果列表的引用数是512个;返回的结果是只读的,因此在不同线程中调用修改它们会冲突。可用的回收策略默认是LRU。

    2.6 二级缓存应用场景

    单表查询时,对于实时性要求不高的请求,可以采用二级缓存并设置缓存刷新间隔来减少数据库访问量,提高访问速度。

    2.7 mybatis二级缓存局限性

    最致命的是,多表查询的情况出现的问题,比如我做订单和用户的多表查询,这个statement可以写在UserMapper.xml或是OrderMapper.xml或者是另创一个xml,假设我把这个statement放进OrderMapper.xml,我多表查询了一次,结果被缓存下来,那么这时候我再去修改user的信息,可是这个更新操作是UserMapper.xml,我们使用mybatis的逆向工程,这两个xml的namespace是不一样的,也就是说这次更新操作没有清空OrderMapper的缓存,那么我下次多表查询就是查到错误的数据。
    解决方法:
    可以加入<cache-ref namespace="mapper.StudentMapper"/>配置,cache-ref代表引用别的命名空间的Cache配置,两个命名空间的操作使用的是同一个Cache。

    也可以是设计一个拦截器,判断涉及到的表,进行更新操作,把有关的表的缓存都清空,不过这样效率有点低。

    mybatis的二级缓存默认是本地的,分布式环境下可能会有过时缓存数据被读取的情况,所以还是放弃mybatis的二级缓存,选择在业务层引入可控制的缓存替代比较好,比如redis等等。

    3. ehcache

    ehcache可以对页面、对象、数据进行缓存,同时支持集群/分布式缓存。

    怎么整合mybatis
    1. 在核心配置文件SqlMapConfig.xml开启mybatis的二级缓存,默认是开启的

    2. 导入ehcache相关jar包

    • ehcache-core-2.6.5.jar
    • mybatis-ehcache-1.0.2.jar
    1. 在classpath下加入ehcache.xml文件


    2. 在XXXMapper.xml中开启二缓存,XXXMapper.xml下的sql执行完成会存储到它的缓存区域(HashMap)


    相关文章

      网友评论

          本文标题:mybatis----缓存

          本文链接:https://www.haomeiwen.com/subject/glpbgftx.html