mybatis的二级缓存

二级缓存是namespace级别的缓存。

1. 开启二级缓存

修改mybatis-config.xml的setting配置

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

修改对应的mapper文件,在namespace下面添加cache的标签

<cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024" />

cache标签可以配置的属性

  • eviction 缓存的相关策略

    • FIFO 先进先出的策略
    • LRU 最近最久未使用调出
    • WEAK 弱引用
    • SOFT 软引用
  • flushInterval 缓存刷新的毫秒数

  • readOnly 是否只读

    • true 是只读,返回引用,速度快但是不安全,同时不要求resultType的POJO类实现Serializable
    • false 通过序列化和反序列化返回,速度比上面的慢同时安全,要求resultType的POJO类实现Serializable,否则会报错
  • size 缓存的大小

  • type 整合第三方缓存的全类名,可以查看github的mybatis项目,上面有各种mybatis整合第三方cache的示例,https://github.com/mybatis
    关键就是实现mybatis的cache接口的方法

2. 效果展示

相关的建表语句啥的见上文。

package com.zihao.test;

import com.zihao.mapper.DeptMapper;
import com.zihao.model.Department;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

/**
 * 二级缓存对于同一namespace的有效
 * 1)<setting name="cacheEnabled" value="true"/> 开启关闭的是二级缓存
 * 2) mapper文件中写明 <cache></cache>
 * 3)readOnly=false的时候 class实现序列化接口
 * 4)对象不是同一个对象 readOnly=false的时候,readOnly=true的时候一个对象
 * 5) 细粒度的控制 <select useCache="false"></> 覆盖上述配置
 * <insert ></> flushCache默认是true, 可以select标签添加flushCache=true,select这个值默认是false的
 * 让一级二级缓存都失效
 * 6) sqlSession.clearCache()清除一级缓存,对二级缓存没影响
 * 7) loadCacheScope 本地缓存作用域,一级缓存SESSION,STATEMENT可以禁用掉1级缓存
 */
public class SecondCacheTest {
    public static void testSecondCacheTest() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2. SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        SqlSession sqlSession1 = sqlSessionFactory.openSession(true);

        //3. 关联mapper文件
        try {
            DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
            DeptMapper deptMapper1 = sqlSession1.getMapper(DeptMapper.class);

            Department department = deptMapper.findDepartmentById(1);
            //关掉才会去拿二级缓存
            sqlSession.close();

            Department departmentCached = deptMapper1.findDepartmentById(1);

            System.out.println(department == departmentCached);

        } finally {
            //4. 关闭连接
            sqlSession1.close();
        }
    }

    public static void main(String[] args) throws IOException {
        testSecondCacheTest();
    }
}

日志输出如下:

DEBUG 06-15 23:37:50,303 Cache Hit Ratio [com.zihao.mapper.DeptMapper]: 0.0  (LoggingCache.java:62) 
DEBUG 06-15 23:37:50,311 ==>  Preparing: select dept_id, dept_name from tbl_dept where dept_id = ?   (BaseJdbcLogger.java:159) 
DEBUG 06-15 23:37:50,352 ==> Parameters: 1(Integer)  (BaseJdbcLogger.java:159) 
DEBUG 06-15 23:37:50,383 <==      Total: 1  (BaseJdbcLogger.java:159) 
DEBUG 06-15 23:37:50,397 Cache Hit Ratio [com.zihao.mapper.DeptMapper]: 0.5  (LoggingCache.java:62) 
false

上面的例子的⚠️点:

  1. 需要关闭一级缓存,才会把一级缓存放到二级缓存,所以sqlSession.close();这句代码执行后,再通过sqlsession1进行查询,会使用
    二级缓存。 如果你把这句语句也放在finally语句里的话,二级缓存是没起作用的。缓存的顺序是先检查二级缓存,然后一级缓存,没有才去查询数据库的。
  2. 虽然只发送了一次sql语句,但是两次查询出来的department对象却是不一样的,原因是缓存配置的时候设置了readOnly="false"的
    原因,如果readOnly="true", 两次结果就是一样的

3. 其他的说明

  • 影响缓存的相关配置
缓存有关的设置 对一级缓存作用 对二级缓存作用
<setting name="cacheEnabled" value="true"/> 没影响 影响二级缓存的开启和关闭,默认是true,建议显式声明
<select useCache="false"> 没影响 影响该select的二级缓存
<select flushCache="true"> 刷新缓存缓存失效,这就是为什么insert导致一级缓存失效的原因,insert的默认flushCache="true" 二级缓存失效
sqlSession.clearCache() 清空一级缓存 对二级缓存没影响
<setting name="loadCacheScope" value=""/> 默认是SESSION,如果改为了STATEMENT的话,一级缓存失效 二级缓存也失效
  • 引用设置的缓存
    可以在namespace中使用如下语句,避免重复设置缓存。
<cache-ref namespace="xxx"/>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,176评论 5 469
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,190评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,232评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,953评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,879评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,177评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,626评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,295评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,436评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,365评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,414评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,096评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,685评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,771评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,987评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,438评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,032评论 2 341

推荐阅读更多精彩内容