详解Mybatis一级缓存和二级缓存

mybatis包含了一个非常强大的查询缓存特性,他可以非常方便的定制和配置缓存。缓存可以极大的提高查询的效率

mybatis系统当中默认定义了两级缓存:一级缓存和二级缓存

一级缓存:默认情况之下,只有一级缓存开启(sqlSession级别的缓存)

二级缓存:需要手动开启配置,需要局域namespace级别的缓存。

一级缓存失效的场景:

sqlSession不同sqlSession相同,查询条件不同sqlSession相同,两次查询之间执行了增删改操作!sqlSession相同,手动清除一级缓存
1.mybatis一级缓存是SqlSession级别的缓存,
2.在操作数据库的时候需要构造sqlsession对象,在对象中有一个数据结构(HashMap)用于存储数据。
3.不同的Sqlsession之间的缓存数据区域是互相不影响的,是独立的
4.一级缓存是框架默认为我们开启的,我们不需要做任何配置
//key:statementId和sql语句
//value:查询结果

一级缓存是sqlsession级别的缓存,也叫本机缓存,因为每一个用户来执行查询的时候都需要sqlsession来执行。为了避免每次都去查询数据库。mybatis把缓存的数据存到sqlsession的本地缓存里面,如果sqlsession里面有的可以直接从本地缓存去读取查询的数据。要是想实现跨Ssqlsession这个级别的话,需要用到二级缓存。就是当多个用户去查询数据的时候,只要有任何一个sqlsession拿到了数据,就会放入到二级缓存里面,其它的sqlsession可以直接从二级缓存里面查询数据。

需要注意的是,如果SqlSession执行了DML操作(增删改),并且提交到数据库,MyBatis则会清空SqlSession中的一级缓存,这样做的目的是为了保证缓存中存储的是最新的信息,避免出现脏读现象

二级缓存:
二级缓存是mapper级别的缓存,多个Sqlsession去操作一个mapper.xml语句,多个sqlseesion共用一个二级缓存,
//key:hashCode + statementId + SQL语句
//value:查询结果
二级缓存开启步骤:
<!‐‐ 开启二级缓存 ‐‐>
<settings>
    <!--开启二级缓存-->
    <setting name="cacheEnabled" value="true"/>
</settings>
<!--使用二级缓存--><cache eviction="FIFO" #收回策略
​
        flushInterval="6000" #刷新间隔
​
        size="512" #引用数目
​
        readOnly="true"/> #只读

eviction回收策略:

LRU(最近最少使用的):移除最长时间不被使用的对象,这是默认值。

FIFO(先进先出):按对象进入缓存的顺序来移除它们。

SOFT(软引用):移除基于垃圾回收器状态和软引用规则的对象。

WEAK(弱引用):更积极地移除基于垃圾收集器状态和弱引用规则的对象。

flushinterval(刷新间隔)

​可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。

默认情况不设置,即没有刷新间隔,缓存仅仅在调用语句时刷新。

size(引用数目)

可以被设置为任意正整数,要记住缓存的对象数目和运行环境的可用内存资源数目。默认值是1024 。

readOnly(只读)​

属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例,因此这些对象不能被修改, 这提供了很重要的性能优势。

可读写的缓存会通过序列化返回缓存对象的拷贝,这种方式会慢一些,但是安全,因此默认是 false。

④. 在select标签上使用二级缓存

<select id="findById" parameterType="int" resultType="User" useCache="true" >
select * from user where id = #{id}
</select>

二级缓存测试:

public class UserTest {
    private InputStream in = null;
    private SqlSession session1 = null;
    private SqlSession session2 = null;
    private UserDao mapper1 = null;
    private UserDao mapper2 = null;

    @Test
    public void findById() throws IOException {
        // 1.加载SqlMapConfig配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建sqlSessionFactory工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //3.sqlSessionFactory创建sqlSession
        SqlSession sqlSession1 = factory.openSession();
        SqlSession sqlSession2 = factory.openSession();

        //4.通过Session创建UserDao接口代理对象
        UserDao mapper1 = sqlSession1.getMapper(UserDao.class);
        UserDao mapper2 = sqlSession2.getMapper(UserDao.class);

        User user1 = mapper1.find(1);
        System.out.println(user1.toString());
        // 将其一级缓存的数据放进二级缓存中,并清空一级缓存
        sqlSession1.commit();

        System.out.println("-----------------");
        User user2 = mapper2.find(1);
        System.out.println(user2.toString());
        System.out.println(user1 == user2);
        // 将其一级缓存的数据放进二级缓存中,并清空一级缓存
        sqlSession2.commit();

        //7.关闭资源
        sqlSession1.close();
        sqlSession2.close();
        resourceAsStream.close();
    }
}

1、一级缓存和二级缓存原理

在sqlsession里面会有一个 executor,每一个executor里面会有一个localcache对象,当用户发起查询的时候,mybatis会根据执行语句,在localcache去查找,如果命中了就直接把这个数据返回,没有的话,再去数据库里面查找出来,ch再写入到localcae里面。所以一级缓存的生命周期是sqlsession。

需要注意的是,在多个sqlsession或者分布式环境下,可能会因为一级缓存,导致一个脏读的情况。

2、二级缓存实现原理是在executor上,引入了一个叫cachingexecutor的一个装饰器, 所以在进入一级缓存之前,会先通过cachingexecutor进行二级缓存 的查询。开启二级缓存之后会被多个sqlsession共享。所以它是一个全局的缓存。所以它的查询流程就变成了先查二级缓存,再查一级缓存,然后再去查数据库。

mybatis的二级缓存相当一级缓存来说,它实现了sqlsession之间缓存数据的一个共享,同时缓存粒度,也能控制到namespace一个级别,并且还通过cache这样的一个接口,来实现不同缓存实现类的一个组合, 对cache的可控也更高了。

关注关注了解更多:

 

posted @   刘百会  阅读(1248)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
历史上的今天:
2019-07-04 java8新特性LocalDate,LocalTime,LoclDateTime使用方法
点击右上角即可分享
微信分享提示