• Mybatis之二级缓存(八)


    1. 介绍

            Mybatis缓存分为一级缓存和二级缓存,在本节中我们介绍下二级缓存的使用及其特性

            MyBatis的一级缓存是在一个Session域内有效的,当Session关闭后,缓存内容也随之销毁。但是Mybatis的一级缓存在Spring中是没有作用的,而我们实际项目中也经常把Mybatis和Spring整合到一起使用。这个时候我们就需要用到二级缓存。

    2. 准备

            请先完成Mybatis之一级缓存(七)章节的内容。

    3. Mybatis二级缓存学习

            1) 开启二级缓存

            Mybatis是默认不开启二级缓存的,要开启二级缓存我们需要做如下准备:

            a. 调整Mybatis.xml,在<configuration>节点中增加<settings><setting name="cacheEnabled" value="true"></settings>。这里是Mybatis二级缓存的总开关。

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

             b. 调整Mapper文件,开启针对Mapper的二级缓存开关。

    <mapper namespace="com.mybatis.dao.CacheDao">
        <cache eviction="FIFO" flushInterval="60000" size="1024" readOnly="true"/>
        .
        .
        .
    </mapper>

            eviction="FIFO"  是缓存的淘汰算法,可选值有"LRU"、"FIFO"、"SOFT"、"WEAK",缺省值是LRU。

            flushInterval="60000"  指缓存过期时间,单位为毫秒,缺省值为空,即只要容量足够,永不过期。  

            size="1024"  缓存容量。

            readOnly="true"  是否只读。

               如果为true, 则所有相同的sql返回的是同一个对象(有助于提高性能,但并发操作同一条数据时,可能不安全)。

               如果为false,则所有相同的sql返回的是同一个对象的副本拷贝。

            c. 调整要缓存的对象,使其实现com.io.Serializabie接口。

    package com.mybatis.entity;
    
    import java.io.Serializable;
    
    public class CacheInfo implements Serializable{
        .
        .
        .
    }

            2) 二级缓存的测试使用

    package com.mybatis;
    
    import java.io.InputStream;
    
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    import com.mybatis.entity.CacheInfo;
    
    @SuppressWarnings("unused")
    public class TestMain {
          
        public static void main(String[] args) {
            InputStream iStream = TestMain.class.getClassLoader().getResourceAsStream("mybatis.xml");
            SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(iStream);
            CacheInfo cacheInfo;
    
            SqlSession session1 = sessionFactory.openSession();
            cacheInfo = session1.selectOne("com.mybatis.dao.CacheDao.getCache1", 1);
            System.out.println("第1次打印  ID:"+cacheInfo.getId()+","+cacheInfo.getTxt());
            session1.close();
    
            SqlSession session2 = sessionFactory.openSession();
            cacheInfo = session2.selectOne("com.mybatis.dao.CacheDao.getCache1", 1);
            System.out.println("第1次打印  ID:"+cacheInfo.getId()+","+cacheInfo.getTxt());
            session2.close();
            
        }
    }

            打印结果为:

    2016-02-22 11:41:06.895 [DEBUG] com.mybatis.dao.CacheDao.getCache1 ==>  Preparing: SELECT * FROM tbCache1 WHERE ID=?  
    2016-02-22 11:41:06.954 [DEBUG] com.mybatis.dao.CacheDao.getCache1 ==> Parameters: 1(Integer) 
    2016-02-22 11:41:07.021 [DEBUG] com.mybatis.dao.CacheDao.getCache1 <==      Total: 1 
    第1次打印  ID:1,111
    .
    .
    .
    2016-02-22 11:41:07.021 [DEBUG] com.mybatis.dao.CacheDao Cache Hit Ratio [com.mybatis.dao.CacheDao]: 0.5
    第2次打印  ID:1,111

            从上面的结果中,可以看到“第2次打印”并没有从数据库中读取数据,而是直接读取的缓存。

    4. 总结及其他

            1)Mybatis的二级缓存可以跨Session访问,但是必须在同一个Session工厂内。

            2)Mybatis的二级缓存更新是以Mapper(确切的说是namespace,因为Mybatis允许多个Mapper对用同一个namespace)为单位的,一个Mapper中的增删改查只能影响到当前Mapper所关联的缓存内容,不同Mapper之间的缓存是相互独立的。

            3)Mybatis的二级缓存的弊端也就显而易见了。假如AMapper中是对A表的增删改查操作,BMapper中是对B表的增删改查操作,CMapper中执行了一个针对A表和B表的联合查找。那么,

                首先,我们执行CMapper的联合查找,然后针对CMapper产生一个缓存对象。

                然后,我们执行AMapper中对A表进行更新操作,由于二级缓存是针对Mapper为单位的,所以此时并不会更新CMapper中的缓存对象。

                在这种情况下,我们再重新执行CMapper的联合查找(查询条件不变),就会读取CMapper中的二级缓存内容,也就会读到脏数据。

            获取有人会说,我们可以把AMapper、BMapper、CMapper合并到一个Mapper中啊?这样会带来另外一些问题:

                首先,这样会导致我们的单个的Mapper文件容量变得极大

                其次,这样会导致这个融合后的Mapper对应的缓存文件不停的被更新,导致效率低下甚至失去缓存意义。

    笔者只是初学者,开此博客的初衷是为了给自己的学习过程留一个痕迹。所以您可能发现笔者措辞不严谨、逻辑不合理,甚至代码有错误、结论很偏颇等等。笔者感激各位的讨论和指正,并在此不胜感激!拜谢!欢迎加QQ群讨论:852410026
  • 相关阅读:
    cocos2d-x C++ 判断当前平台宏定义大全
    cocos2d-x JS 纯代码加载播放plist与png动画
    cocos2d-x JS 加载播放Studio帧动画的两种方法
    iOS开发小技巧总结
    cocos2d-x C++ (Android)集成第三方微信分享
    cocos2d-x C++ (iOS)集成第三方微信分享
    cocos2d-x JS 获取当前系统时间(解决屏幕双击点击事件)
    (已解决) eclipse提示报错"serializing cdt project settings"解决方案
    cocos2dx
    cocos2d-X JS 获取cocostudio中的UI组件
  • 原文地址:https://www.cnblogs.com/LOVE0612/p/5210152.html
Copyright © 2020-2023  润新知