• mybatis 缓存


    6. MyBatis缓存

    1. 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其生命周期为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。

    2. 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。

    3. 对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。

    面试必考

    1.缓存应用场景

    查询频率比较高,而且数据信息不经常变动。客户档案定义 ,托运部定义。

    2.缓失效的问题

    缓存是有过期事件的 。

    滑动过期:从最后一次使用开始往后推算一段时间

    绝对过期:一段时间内一定会失效

    3.缓存是一把双刃剑

    哲学:缓存,快,高速,

    容易炸,使用不当,起不到加速查询的作用。

    Redis ----------->D

    4.缓存的存储结构

    session 的底层map集合 key value

    5.第三方缓存插件

    EhCache

    查询缓存的使用,主要是为了提高查询访问速度。将用户对同一数据的重复查询过程简化,不再每次均从数据库查询获取结果数据,从而提高访问速度。

    6.1 缓存原理
    6.2 缓存分类

    MyBatis查询缓存机制。根据缓存区的作用域与生命周期,可划分为两种:一级缓存和二级缓存。

      MyBatis查询缓存的作用域是根据映射文件的namespace划分的,相同的namespace的mapper查询数据放在同一个缓存区域。不同namespace下的数据互不干扰。无论是一级缓存还是二级缓存,都是按照namespace进行分别存放的。

      但是一级、二级缓存的不同之处在于,SqlSession一旦关闭,则SqlSession中的数据将不存在,即一级缓存就不复存在。而二级缓存的生命周期与整个应用同步,与SqlSession是否关闭无关。换句话说,一级缓存是在同一线程(同一SqlSession)间共享数据,而二级缓存是在不同线程(不同的SqlSession)间共享数据。

    6.3 一级缓存
    6.3.1 一级缓存--从缓存中查找数据的依据:

    缓存的底层实现是一个Map,Map的value是查询结果

    Map的key,即查询依据,使用的ORM架构不同,查询依据是不同的

    MyBatis的查询依据是:Sql的id+SQL语句

    Hibernate的查询依据是:查询结果对象的id

    测试:

    @Test

    public void show(){

    List<Result> list=null;

    SqlSession session= UtilMybatis.getsession();

    try {

    list= session.getMapper(ResultDao.class).findAllResult();

    } catch (Exception e) {

    e.printStackTrace();

    }

    for(Result result:list){

    System.out.println(result);

    }

    System.out.println("==========一级缓存===========");

    try {

    list= session.getMapper(ResultDao.class).findAllResult();

    } catch (Exception e) {

    e.printStackTrace();

    }finally {

    UtilMybatis.closesession(session);

    }

    for(Result result:list){

    System.out.println(result);

    }

    }

    结果:sql只执行一次后将id与sql 存储在一级缓存内(使用同一个session)

    6.3.2 增、删、改对一级缓存的影响

    增删改会清空一级缓存:注意:必须使用insert标签,不能使用select,否则实验做不成功

    测试:

    public void show() throws Exception {

    List<Result> list=null;

    SqlSession session= UtilMybatis.getsession();

    try {

    list= session.getMapper(ResultDao.class).findAllResult();

    } catch (Exception e) {

    e.printStackTrace();

    }

    for(Result result:list){

    System.out.println(result);

    }

    System.out.println("==========增加===========");

    Result result1=new Result();

    result1.setAge(18);

    result1.setScore(80);

    result1.setSubjectName("shuxue");

    Integer count=session.getMapper(ResultDao.class).adderesult(result1);

    System.out.println(count);

    System.out.println("==========一级缓存===========");

    try {

    list= session.getMapper(ResultDao.class).findAllResult();

    } catch (Exception e) {

    e.printStackTrace();

    }finally {

    UtilMybatis.closesession(session);

    }

    for(Result result:list){

    System.out.println(result);

    }

    }

    结果:session用同一个,在添加后在查询因(增加清空一级缓存)故在进行db查询

    6.3.2 内置二级缓存(在同一mapper.xml文件中)

           由于MyBatis从缓存中读取数据的依据与SQL的id相关,而非查询出的对象。所以,使用二级缓存的目的,不是在多个查询间共享查询结果(所有查询中只要查询结果中存在该对象,就直接从缓存中读取,这是对查询结果的共享,Hibernate中的缓存就是为了在多个查询间共享查询结果,但MyBatis不是),而是为了防止同一查询(相同的Sql id,相同的sql语句)的反复执行。

    https://my.oschina.net/KingPan/blog/280167

    http://www.mamicode.com/info-detail-890951.html

    http://blog.csdn.net/isea533/article/details/44566257

    http://blog.csdn.net/u010676959/article/details/43953087

    http://blog.csdn.net/xiadi934/article/details/50786293

    如何开启二级缓存,二级缓存在Mybatis默认是开启(全局配置的某个属性值为true)的,但是开始和能直接使用时两码事。

    1.你cacheEnabled=true,默认值为true

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

    2.你得在Mapper文件中,<cache/>

    <cache

    eviction="FIFO"

    flushInterval="60000"

    size="512"

    readOnly="true"/>

    这个更高级的配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,

    而且返回的对象被认为是只读的

    3.Entity Implements Serializable(实体类序列化)

    缓存中对象可用的收回策略

    LRU – 最近最少使用的:移除最长时间不被使用的对象。

    FIFO – 先进先出:按对象进入缓存的顺序来移除它们。

    SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。

    WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

    默认的是 LRU。

    flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒 

    形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。

    size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的 

    可用内存资源数目。默认值是 1024。

    readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回

    缓 存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。

    可读写的缓存 会返回缓存对象的拷贝(通过序列化) 。这会慢一些,但是安全,因此默认是 false。

    6.3.4. 增删改对二级缓存的影响

     1.增删改也会清空二级缓存

          2.对于二级缓存的清空实质上是对value清空为null,key依然存在,并非将Entry<k,v>删除

          3.从DB中进行select查询的条件是:

                  1.缓存中根本不存在这个key

                  2.存在key对应的Entry,但是value为null

    二级缓存的关闭

    全局关闭:

    局部关闭

    二级缓存的使用原则

    1.多个namespace不要操作同一张表

    2.查询大于修改的情况下使用

    6.3.5 引入第三方插件Mybatis集成EhCache

    在MyBatis中通过ehcache配置二级缓存

    1.jar包

    <dependency>

    <groupId>net.sf.ehcache</groupId>

    <artifactId>ehcache</artifactId>

    <version>2.10.4</version>

    </dependency>

    <dependency>

    <groupId>org.mybatis.caches</groupId>

    <artifactId>mybatis-ehcache</artifactId>

    <version>1.1.0</version>

    </dependency>

       2.在小配置中添加一个缓存类

    在小配置中输入EhcacheCache 并选中 双击shift

    点击EhcacheCache 出现

    鼠标右击出现

    粘贴在

    粘贴前:

    粘贴后:

       3.在src下植入ehcache.xml文件

    <ehcache>

    <diskStore path="java.io.tmpdir"/>

    <defaultCache

    maxElementsInMemory="10000"

    eternal="false"

    timeToIdleSeconds="120"

    timeToLiveSeconds="120"

    overflowToDisk="true"

    />

    <cache name="sampleCache1"

    maxElementsInMemory="10000"

    eternal="false"

    timeToIdleSeconds="300"

    timeToLiveSeconds="600"

    overflowToDisk="true"

    />

    <cache name="sampleCache2"

    maxElementsInMemory="1000"

    eternal="true"

    timeToIdleSeconds="0"

    timeToLiveSeconds="0"

    overflowToDisk="false"

    /> -->

    </ehcache>

    测试: public void show() throws Exception {

    List<Result> list=null;

    SqlSession session= UtilMybatis.getsession();

    try {

    list= session.getMapper(ResultDao.class).findAllResult();

    } catch (Exception e) {

    e.printStackTrace();

    }finally {

    UtilMybatis.closesession(session); //session关闭

    }

    for(Result result:list){

    System.out.println(result);

    }

    System.out.println("========二级缓存=============");

    SqlSession session1= UtilMybatis.getsession();

    try {

    list= session1.getMapper(ResultDao.class).findAllResult();

    } catch (Exception e) {

    e.printStackTrace();

    }finally {

    UtilMybatis.closesession(session1);

    }

    for(Result result:list){

    System.out.println(result);

    }

    }

    结果:sql语句执行一次

  • 相关阅读:
    PredictionIO+Universal Recommender快速开发部署推荐引擎的问题总结(1)
    SpringJDBC的JdbcTemplate在MySQL5.7下不支持子查询的问题
    POP3接收邮件
    发送邮件
    电子邮件介绍
    线程优先级队列
    线程同步
    threading模块
    _thread模块
    使用线程
  • 原文地址:https://www.cnblogs.com/Java60-123456/p/10678654.html
Copyright © 2020-2023  润新知