MyBatis之缓存的使用

95 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第9天,点击查看活动详情

1、前言

MyBatis 内置了一个强大的事务性查询缓存机制,可以非常方便地配置和定制。默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:

<cache/>

在进行配置的时候还会分为一级缓存和二级缓存:

一级缓存:线程级别的缓存,是本地缓存,sqlSession级别的缓存

二级缓存:全局范围的缓存,不止局限于当前会话

2、 一级缓存的使用

一级缓存是sqlsession级别的缓存,默认是存在的。比如:我发送两个相同的查询请求,但是sql语句却只执行了一次,也就是说第一次查询的时候已经将结果进行了缓存。

@Test
public void test() {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    try {
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        List<User> list = mapper.selectUsers();//第一次查询
        for (User user : list) {
            System.out.println(user);
        }
        List<User> list2 = mapper.selectUsers();//第二次查询,从缓存中取数据
        for (User user : list2) {
            System.out.println(user);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        sqlSession.close();
    }
}

注:一级缓存可能会失效,比如下面几种情况

2.1 开启多个sqlsession

因为一级缓存是sqlSession级别的缓存,所以程序中只要开启了多个sqlsession,一级缓存就会失效

@Test
public void test02(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserDao mapper = sqlSession.getMapper(UserDao.class);
    List<User> list = mapper.selectUsers();
    for (User user : list) {
        System.out.println(user);
    }
    System.out.println("================================");
    SqlSession sqlSession2 = sqlSessionFactory.openSession();
    UserDao mapper2 = sqlSession2.getMapper(UserDao.class);
    List<Emp> list2 = mapper2.selectUsers();
    for (User user : list2) {
        System.out.println(user);
    }
    sqlSession.close();
    sqlSession2.close();
}

2.2 手动清空缓存

两次查询的过程中,通过sqlSession.clearCache();清空缓存,缓存就失效了。

2.3 参数原因

执行查询的SQL语句的过程中,如果参数不一致,也会造成缓存失效。

2.4 数据修改

执行第一次查询后,如果数据修改了,那么缓存也会失效。

3、二级缓存

二级缓存是全局作用域缓存,默认关闭,需要手动进行配置。 Mybatis提供二级缓存的接口以及实现,缓存实现的时候要求实体类实现Serializable接口,二级缓存在sqlSession关闭或提交之后才会生效。

3.1 使用缓存

以下三个步骤,缺一不可。

3.1.1 开启二级缓存

在全局配置文件中,通过如下配置,开启二级缓存

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

3.1.2 添加<cache/>标签

在需要使用二级缓存的映射文件增加 <cache/>标签,如一级缓存一样。

3.1.3 实体类必须要实现Serializable接口