mybatis 一级缓存和二级缓存简介

正如大多数持久层框架一样,MyBatis 同样提供了一级缓存二级缓存的支持

  1. 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空

  2. 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace)并且可自定义存储源,如 Ehcache。作用域为namespance是指对该namespance对应的配置文件中所有的select操作结果都缓存,这样不同线程之间就可以共用二级缓存。

启动二级缓存:在mapper配置文件中:<cache readOnly="true"/>。

二级缓存可以设置返回的缓存对象策略:<cache readOnly="true">。当readOnly="true"时,表示二级缓存返回给所有调用者同一个缓存对象实例,调用者可以update获取的缓存实例,但是这样可能会造成其他调用者出现数据不一致的情况(因为所有调用者调用的是同一个实例)。当readOnly="false"时,返回给调用者的是二级缓存总缓存对象的拷贝,即不同调用者获取的是缓存对象不同的实例,这样调用者对各自的缓存对象的修改不会影响到其他的调用者,即是安全的,所以默认是readOnly="false";


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

     4. 一级缓存测试实例:

(实例1)

/**
     * 测试mybatis一级缓存,即session作用域缓存
     */
    @Test
    public void testSelect_sessionCache() {
        String statement = "com.xpspeed.centralcms.persist.mybatis.mapper.CommandFileMapper.select";
        SqlSession session = SqlSessionUtil.openSession();
        CommandFile commandFile1 = session.selectOne(statement,4l);
        CommandFile commandFile2 = session.selectOne(statement,4l);
        //commandFile2是从一级缓存中返回的缓存对象,与commandFile1同一个对象实例。
        Assert.assertEquals(commandFile1, commandFile2);
        //session关闭时清空缓存
        session.close();
        //显示清空缓存
//            session.clearCache();
        session = SqlSessionUtil.openSession();
        CommandFile commandFile3 = session.selectOne(statement,4l);
        //查询时commandFile3,一级缓存已经被清空,commandFile3与commandFile1不是同一个对象实例
        Assert.assertNotEquals(commandFile1, commandFile3);
        CommandFile commandFile4 = session.selectOne(statement,5l);
        //一级缓存中不存在id为5的缓存对象,所以commandFile4是从数据库中查找出的实例。
        Assert.assertNotEquals(commandFile3, commandFile4);
    }

实例2)

在实例1中将session.close()换为执行一个update语句,也会导致一级缓存清空。

/**
     * 测试mybatis一级缓存,即session作用域缓存
     */
    @Test
    public void testSelect_sessionCache2() {
        String statement = "com.xpspeed.centralcms.persist.mybatis.mapper.CommandFileMapper.select";
        SqlSession session = SqlSessionUtil.openSession();
        CommandFile commandFile1 = session.selectOne(statement,4l);
        //执行更新后清空缓存
        commandFile1.setName("bigfile-uploader2");
        session.update("com.xpspeed.centralcms.persist.mybatis.mapper.CommandFileMapper.update",commandFile1);
        CommandFile commandFile2 = session.selectOne(statement,4l);
        //查询commandFile2时,一级缓存已经被清空,commandFile2与commandFile1不是同一个对象实例
        Assert.assertNotEquals(commandFile1, commandFile2);
    }

5.二级缓存测试实例

在配置文件中启动该namespace的二级缓存:<cache readOnly="false"/>

示例1:

/**
     * 测试mybatis二级缓存:nameSpace作用域
     * <cache readOnly="false"/>
     */
    @Test
    public void testSelect_nameSpaceCache() {
        String statement = "com.xpspeed.centralcms.persist.mybatis.mapper.CommandFileMapper.select";
        SqlSession sqlSession1 = SqlSessionUtil.openSession();
        SqlSession sqlSession2 = SqlSessionUtil.openSession();

        //使用二级缓存时,CommandFile类必须实现一个Serializable接口
        CommandFile commandFile1 = sqlSession1.selectOne(statement, 4l);
        //sqlSession1提交后才会把数据放到二级缓存中,sqlSession2才能使用二级缓存
        sqlSession1.commit();
        CommandFile commandFile2 = sqlSession2.selectOne(statement, 4l);
        /**
         * <cache readOnly="false"/>时,返回缓存对象的拷贝,所以返回的commandFile2 != commandFile1
         * 这样一个调用者有修改这个自己的缓存对象时,其他调用者不受影响。
         */
       Assert.assertNotEquals(commandFile1, commandFile2);
    }

示例2:二级缓存设置<cache readOnly="true"/>

/**
     * 测试mybatis二级缓存:nameSpace作用域
     * <cache readOnly="true"/>
     */
    @Test
    public void testSelect_nameSpaceCache2() {
        String statement = "com.xpspeed.centralcms.persist.mybatis.mapper.CommandFileMapper.select";
        SqlSession sqlSession1 = SqlSessionUtil.openSession();
        SqlSession sqlSession2 = SqlSessionUtil.openSession();

        //使用二级缓存时,CommandFile类必须实现一个Serializable接口
        CommandFile commandFile1 = sqlSession1.selectOne(statement, 4l);
        //sqlSession1提交后才会把数据放到二级缓存中,sqlSession2才能使用二级缓存
        sqlSession1.commit();
        CommandFile commandFile2 = sqlSession2.selectOne(statement, 4l);
        /**
         * <cache readOnly="true"/>时,对所有调用者返回同一个缓存对象,即同一个实例。
         * 这样一个调用者有修改这个缓存对象时,其他调用者可能就会出现数据不一致的问题。
         */
        Assert.assertEquals(commandFile1, commandFile2);
    }

实例3:

/**
     * 测试mybatis二级缓存:nameSpace作用域
     * 执行update操作,会清空二级缓存
     */
    @Test
    public void testSelect_nameSpaceCache3() {
        String statement = "com.xpspeed.centralcms.persist.mybatis.mapper.CommandFileMapper.select";
        SqlSession sqlSession1 = SqlSessionUtil.openSession();
        SqlSession sqlSession2 = SqlSessionUtil.openSession();
        SqlSession sqlSession3 = SqlSessionUtil.openSession();

        //使用二级缓存时,CommandFile类必须实现一个Serializable接口
        CommandFile commandFile1 = sqlSession1.selectOne(statement, 4l);
        //sqlSession1提交后才会把数据放到二级缓存中,sqlSession2才能使用二级缓存
        sqlSession1.commit();
        CommandFile commandFile2 = sqlSession2.selectOne(statement, 4l);
        /**
         * <cache readOnly="true"/>时,对所有调用者返回同一个缓存对象,即同一个实例。
         * 这样一个调用者有修改这个缓存对象时,其他调用者可能就会出现数据不一致的问题。
         */
        Assert.assertEquals(commandFile1, commandFile2);
        commandFile2.setName("bigfile-uploader");
        sqlSession2.update("com.xpspeed.centralcms.persist.mybatis.mapper.CommandFileMapper.update", commandFile2);
//      执行commit()表示执行update操作,会清空二级缓存中的数据
        sqlSession2.commit();
        CommandFile commandFile3 = sqlSession3.selectOne(statement, 4l);
        //查询时,二级缓存中没有缓存数据了
        Assert.assertNotEquals(commandFile2, commandFile3);
    }

  • 0
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值