Mybatis (四) 缓存机制

许多运用程序为了提高性能而增加缓存,特别是从数据库中获取的数据,如果缓存中没有,就到表中去查询,表查询的数据添加到缓存中去,下次查询是直接从缓存中读取,Mybatis 包含一个非常强大的查询缓存特性,它可以非常方便的配置和定制,缓存可以极大的提升查询效率。就如同第一次访问某网站时耗时会就一下感觉到卡,关闭网页再访问相同网页时就流畅了很多,所以缓存机制是很重要的。

一、mybatis 的一级缓存

在默认情况下,mybatis 的一级缓存是默认开启的,类似与hiberante,所谓一级缓存也就是基于一个 sqlsession 的查询语句, 即 session 级别的缓存,非全局缓存或者称为非二级缓存。
一级缓存(local cache),即本地缓存,作用域默认为 sqlsession ,当 Session close 后,该 session 中所有 Cache 将被清空,本地缓存不能被关闭,但可以调用 clearCache() 来清空本地缓存。

  • 一级缓存失效的四种情况:
  1. 不同 SqlSession 对应不同的一级缓存
  2. 同一个 SqlSession 但是查询条件不同
  3. 同一个 SqlSession 两次查询期间执行了任何一次增删改的操作
  4. 同一个 SqlSession 两次查询手动清空了缓存

UserMapping.xml

<resultMap type="cn.softjx.modle.User" id="UserMap">
        <result column="t_id" property="id"/>
        <result column="t_username" property="username"/>
        <result column="t_password" property="password"/>
        <result column="t_sid" property="sid"/>
    </resultMap>

   <select id="selectAll2" resultMap="UserMap" >
        select t_id,t_username,t_password from t_user;
    </select>

映射文件不做任何处理,mybatis默认一级缓存
Test.java

@Test
    public void testSelect(){
        try {                   
            List<User> user=mapper.selectAll2();
            for(User users:user){
                System.out.println(users.getPassword()+"  "+users.getUsername()+"   "+users.getSid());
            }
            List<User> user1=mapper.selectAll2();
            for(User users:user1){
                System.out.println(users.getPassword()+"  "+users.getUsername()+"   "+users.getSid());
            }                       
        } finally{
            // TODO Auto-generated catch block
            session.close();
        }
    }

声明了两个不同的 user 对象,但都是在同一个 Session 内执行查询的,代码虽然执行了两次数据库的查询,但是实际上只是在数据库查询了一次并将其缓存在同一 Session 中,再使用同一个 Session 查询同一字段时直接读取一级缓存中的数据内容。

一级缓存.png

总共打印了18条数据,从 log4j 的打印结果可以看出从数据库中查询出9条数据,并且只是发送了一次 SQL 语句。
注意:
1. 用同一 Session 但查询条件不同缓存失效
2. 用同一 Session 在第二次查询前执行了任何造成数据库改动的操作(CRDU)
再使用同一句查询语句缓存失效

二、Mybatis 二级缓存

如果要实现 mybatis 的二级缓存,二级缓存需要手动开启和配置,它是基于 namespace 级别的缓存,全局作用域缓存,一般来说有两种方式 :

  1. 采用 mybatis 内置的 cache 机制
  2. mybatis 定义了缓存接口 Cache,我们可以通过实现 Cache 接口来定义二级缓存,可采用第三方 Cache 框架。
  • 采用 mybatis 内置的 cache 机制

在表映射文件中加入 <cache /> 语句,并且相应的 model 要实现 java 的 Serializable 接口,因为二级缓存就是序列化和反序列化的过程,<cache /> 表示:

  1. 所有在映射文件里的 select 语句都将被缓存
  2. 所有在映射文件里的 insert,update 和 delete 语句会被清空缓存。
  3. 缓存不会被设定的时间所清空。
  4. 每个缓存可以存储 1024 个列表或对象的引用
  5. 缓存将作为 “读/写” 缓存,意味着获取对象不是共享的且对调用者是安全的,不会有其他的调用者或线程潜在修改。

使用步骤 :

  1. 全局配置文件中开启二级缓存,默认是打开的
    <setting name="cacheEnabled" value="ture" />
  2. 需要使用二级缓存的映射文件处理使用 cache 配置缓存
  3. POJO需要实现 Serializable 接口
  4. 如果会话关闭:一级缓存的数据会保存到二级缓存中,新的会话查询信息就可以参照二级缓存中的内容,二级缓存会在 SqlSession 关闭或提交后才会生效。

bean.java 实现序列化

public class User implements Serializable{
    private Integer id;
    private String username;
    private String password;
    private Integer sid;
    
    private School school;
    
    
    public User() {
                
    }
}

config.xml

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

Mapping.xml 配置 <cache /> 标签

<mapper namespace="cn.softjx.dao.inter.UserMapping">
    
<cache />                  
    <resultMap type="cn.softjx.modle.User" id="UserMap">
        <result column="t_id" property="id"/>
        <result column="t_username" property="username"/>
        <result column="t_password" property="password"/>
        <result column="t_sid" property="sid"/>
       ......

在 Test.java 中声明三个不同的 session 执行相同的查询

                User useBean=new User();
                useBean.setId(4);
                List<User> user=mapper.selectAll3(useBean);
                for(User users:user){
                    System.out.println(users.getPassword()+"  "+users.getUsername()+"   "+users.getSid());
                }
                                            
                
                session.close();
                
                UserMapping mapper1=session1.getMapper(UserMapping.class);
                
                List<User> user1=mapper1.selectAll3(useBean);
                for(User users:user1){
                    System.out.println(users.getPassword()+"  "+users.getUsername()+"   "+users.getSid());
                }
                                                
                session1.close();
            
                UserMapping mapper2=session2.getMapper(UserMapping.class);              
                List<User> user2=mapper2.selectAll3(useBean);
                for(User users:user2){
                    System.out.println(users.getPassword()+"  "+users.getUsername()+"   "+users.getSid());
                }                                                               
                session2.close();
结果.png
image.png

虽然使用了不同的 Session 但只发送了一条 SQL。即不同的sqlSession可以共享一个 Mapping
日志中有一个 Hit Ratio 命中率,它是如何计算的呢。第一次查询由于缓存中是没有数据的所以是 0.0,第二次查询从缓存中取 1-(1/2)=0.5,第三次查询
1-(1/3)=0.666666

cache 标签中还有几个属性 eviction , flushInterval ,readOnly

  • eviction:
  1. LRU :最近不使用的缓存数据,移出最长时间不被使用的数据
  2. FIFO :先进先出
  3. SOFT : 软引用,移除基于垃圾回收器状态和软引用规则对象
  4. WEAK :软引用,更积极的垃圾回收器状态和软引用规则对象
    ,默认是 LRU
  • flushInterval :缓存刷新清空时间,默认不刷新

  • readOnly :是否进行只读操作,如果只进行只读操作当数据库内的值发送变化时,缓存值马上改变得到的数据还是原有的为进行修改的数据。

上篇:Mybatis (三)动态sql:http://www.jianshu.com/p/71c0cdd9c249

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容