Mybatis的缓存

Posted -杨杨杨-

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis的缓存相关的知识,希望对你有一定的参考价值。

1.缓存是什么 

  在 Mybatis 里面,所谓的缓存就是将已经查询过的记录放在内存的缓冲区或文件上,这样如果再次查询,可以通过配置的策略,命中已经查询过的记录,从而提高查询的效率。

  Mybatis 的缓存分为一级缓存和二级缓存。

2.一级缓存

  一级缓存:所谓的一级缓存就是会话级别的缓存,就是同一个会话,如果已经查询过的数据会保存一份在内存中,如果会话没有关闭,再次调用同样的方法查询,不会再查询数据库,,而是直接从缓存中取出之前查询的数据.。一级缓存默认是打开的,而且是关闭不了的。一下代码,调用了 5 次 findAll 方法,但执行只查询了一次数据库。说明默认一级缓存是打开的。

@Test
    public void findAll(){
        try {
            //1.获得操作对象
            SqlSession session = DbUtils.getSession();
            //2.使用 session.获得映射接口的代理对象,这个代理对象是 mybatis 通过StudentMapper.xml 创建的
            StudentMapper studentMapper = session.getMapper(StudentMapper.class);
            List<Student> list = studentMapper.findAll();
            List<Student> list1 = studentMapper.findAll();
            List<Student> list2 = studentMapper.findAll();
            List<Student> list3 = studentMapper.findAll();
            List<Student> list4 = studentMapper.findAll();
            for(Student s:list4){
                System.out.print("姓名:"+s.getSname());
                System.out.print(",年龄:"+s.getAge());
                System.out.println(",生日:"+s.getBirthday());
            }
            session.commit();
            session.close();
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}    
查看代码

  --重点查看控制台输出了多少条 SQL,来分析一级缓存是存在。
结论:调用了五次方法,查询了五次相同数据。但后台输出的是一条 SQL 语句,说明默
认就支持一级缓存的。

 

2.1如何清空一级缓存

  1.关闭会话.close()
  2.进行了操作(增删改),提交了 commit();
  3.手工清除缓存 clearCache() 一下代码,手工清除了一次缓存,操作数据一次,所以会查询三次数据库

@Test
    public void findAll(){
        try {
            SqlSession session = DbUtils.getSession();
            StudentMapper studentMapper =             
            session.getMapper(StudentMapper.class);
            List<Student> list = studentMapper.findAll();
            //清除一级缓存
            session.clearCache();
            List<Student> list1 = studentMapper.findAll();
            //操作数据库,一级缓存会清除
            studentMapper.deleteByIds(3);
            List<Student> list2 = studentMapper.findAll();
            List<Student> list3 = studentMapper.findAll();
            List<Student> list4 = studentMapper.findAll();
            for(Student s:list4){
                System.out.print("姓名:"+s.getSname());
                System.out.print(",年龄:"+s.getAge());
                System.out.println(",生日:"+s.getBirthday());
            }    
            session.commit();
            session.close();
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}        
查看代码

3.二级缓存

  所谓二级缓存其实就是文件级别的缓存。 有效范围就是同一个映射文件,即使关闭会话都不会清空的缓存!

  内置二级缓存的配置
  1.在映射文件增加一个二级缓存的配置

  2.二级缓存需要将Java 的对象序列化到本地。实体类要增加一个序列化接口Serializable所谓的序列化(串行化),就是将对象变成一个流格式。这样对象就可以完成保存到本地或者网络传递!

public class Student implements Serializable {
    private Integer sid;
    private Integer aid;
    private String sname;
    private String sex;
    private Date birthday;
    private Integer age;

    public String getSname() {
        return sname;
    }
    public void setSname(String sname) {
        this.sname = sname;
    }
    public Integer getSid() {
        return sid;
    }
    public void setSid(Integer sid) {
        this.sid = sid;
    }
    public Integer getAid() {
        return aid;
    }
    public void setAid(Integer aid) {
        this.aid = aid;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
}        
查看代码

  3.新版本已经默认支持开启二级缓存.可以不改

<settings>
    <!-- 默认支持骆驼命名法 -->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
    <!-- 启动缓存,新版本已经默认支持了,可以不配置 -->
    <setting name="cacheEnabled" value="true"/>
</settings>
查看代码

结果:内置的二级缓存发现缓存的命中率很低,基本不起作用

 

那么如何解决这个缺陷?

  使用第三方的缓存 ehcache,而ehcache 需要 slf4j 这个日志包支持

3.1ehcache 的整合配置

  1.导入包

  

  2.配置第三方缓存

<cache type="org.mybatis.caches.ehcache.EhcacheCache" >
    <!--最大的空闲时间 -->
    <property name="timeToIdleSeconds" value="10000"/>
    <!-- 最大的在线时间 -->
    <property name="timeToLiveSeconds" value="20000"/>
    <!-- 内存的大小 b 字节 m1 =1024k 1k=1024b -->
    <property name="maxEntriesLocalHeap" value="2000000"/>
    <!-- 文件的大小 b 字节-->
    <property name="maxEntriesLocalDisk" value="20000000"/>
    <!-- 算法 LRU:最少使用优先, "LFU" or "FIFO:先进先出 -->
    <property name="memoryStoreEvictionPolicy" value="LRU"/>
</cache>
查看代码

结果:命中率 100%

  什么是命中率,就是已经查询的数据,在找到的几率。使用同样的方法时,可以匹配原来的数据的概率;就是第二次以后的查询,找回第一查询的数据的概率,数据少的时候基本都是 100%。

以上是关于Mybatis的缓存的主要内容,如果未能解决你的问题,请参考以下文章

Mybatis复杂查询动态sql及缓存详解

Mybatis 学习笔记总结

推荐学java——MyBatis高级

推荐学java——MyBatis高级

推荐学java——MyBatis高级

推荐学java——MyBatis高级