浅谈MyBatis二级缓存

一、二级缓存介绍
我们知道MyBatis 提供了一级缓存来减轻数据库的压力,但是一级缓存是一个SqlSession(会话)级别的缓存,这也就意味着一级缓存的适用范围比较小。在一级缓存的基础上,MyBatis 提供了二级缓存机制,二级缓存是一个namespace级别的缓存,相对于一级缓存而言,二级缓存允许跨SqlSession工作,因此二级缓存的作用范围更大。

有关一级缓存可参考博文:
https://blog.csdn.net/codejas/article/details/79545367

二、二级缓存运行机制
每个SqlSession在执行查询操作的时候,都会将查询的结果放在当前会话的一级缓存中。如果当前会话关闭,一级缓存中的数据会被保存在二级缓存中。因此二级缓存是在一级缓存的基础上进行扩展的,不同的namespace查出的数据都会将数据存在自己对应的缓存中,这些缓存信息使用Map存储。

需要注意的地方是:MyBatis 在开启二级缓存的情况下,如果发出了一条SQL 查询语句,会先向二级缓存中查询是否有对应的缓存数据,如果没有再接着查询一级缓存中的数据,如果一级缓存中也没有对应的缓存数据,才会向数据库发送SQL。下面附一张蹩脚的二级缓存运行机制图。

三、实现二级缓存的步骤
1.在MyBatis 全局配置文件中开启二级缓存的配置,默认也是开启的,建议自己设置为开启的。

2.在对应的SQL 映射文件中加入<cache/>标签。

3.将返回的JavaBean 数据类型的类实现Serializable(序列化)接口。

知道了二级缓存的实现方式,下面就来体会一下二级缓存带来的作用。

四、二级缓存初体验
MyBatis 全局配置文件:

1    <!-- 配置二级缓存,默认也是开启的,建议手动设置一下 -->
2    <setting name="cacheEnabled" value="true"/>


POJO 实现序列化接口:

package com.jas.mybatis.bean;

import java.io.Serializable;

public class Department implements Serializable{
    private Integer id;
    private String departmentName;

    //省略get、set 与toString 方法
}


mapper 接口:

    Department getDeptById(Integer id);

SQL 映射文件:

    <!--
        在需要使用二级缓存的SQL 映射文件中添加 <cache/> 标签

        相关的一些参数介绍:
        eviction:缓存回收策略
        flushInterval:缓存刷新时间,单位是毫秒,默认不刷新
        size:可存储多少个缓存对象,只能是正整数,合理的设置可以防止内存泄漏
        readOnly:是否只读
    -->
    <cache/>
    <select id="getDeptById" resultType="com.jas.mybatis.bean.Department">
        SELECT id, dept_name departmentName FROM t_dept WHERE id = #{id}
    </select>

测试代码:

    // 用于返回SqlSessionFactory  对象
    private SqlSessionFactory getSqlSession() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream is = Resources.getResourceAsStream(resource);

        return new SqlSessionFactoryBuilder().build(is);  
    }

    @Test
    public void secondLevelTest() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSession();

        //创建两个不同的会话
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();

        DepatmentMapper depatmentMapper1 = sqlSession1.getMapper(DepatmentMapper.class);
        DepatmentMapper depatmentMapper2 = sqlSession2.getMapper(DepatmentMapper.class);

        Department department1 = depatmentMapper1.getDeptById(1);
        System.out.println(department1);    
        // 关闭当前的会话1, 否则二级缓存不起作用
        sqlSession1.close();

        Department department2 = depatmentMapper2.getDeptById(1);
        System.out.println(department2);
        // 关闭会话2
        sqlSession2.close();

    }


测试结果:

当会话1 查询结束并关闭后,我们使用另一个会话执行与会话1 相同的SQL 查询语句,发现并没有发送SQL 语句,因为缓存中已经保存了要查询的数据,这次直接从缓存中获取数据,这就是MyBatis 提供的跨会话级别(SqlSession)的二级缓存机制。

五、与缓存相关的设置
1.可以在MyBatis 全局配置文件中的setting标签中配置cacheEnabled属性,表示是否启用二级缓存机制,不过不影响一级缓存。

2.select查询标签中可以设置useCache属性,配置是否使用二级缓存,默认一级缓存是一直生效的。

3.sqlSession.clearCache();方法默认只清除一级缓存中的数据。

4.可以在每个增删改的标签中设置flushCache属性,设置为true后,如果执行了该增删改操作,则一级缓存与二级缓存中的数据都会清空。

六、总结
这篇博客主要对MyBatis 中的二级缓存机制做了介绍,在实际开发的过程中,MyBatis 提供的二级缓存机制好像并没有获得开发人员的青睐。原因是二级缓存是一个namespace级别的缓存,如果在不同的namespace下操作同一SQL 语句,可能导致缓存中的数据不正确。在进行多表联查的时候,也可能会导致二级缓存中的数据不正确。所以在实际的开发过程中要慎用二级缓存。
————————————————
版权声明:本文为CSDN博主「留兰香丶」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/codejas/article/details/79547932

posted @   李白白白白白  阅读(214)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示