Mybatis框架(十四)Mybatis的缓存

什么是缓存?

  • 存在内存中的临时数据。

  • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,

  • 从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。

为什么使用缓存?

  • 减少和数据库的交互次数,减少系统开销,提高系统效率。

什么样的数据能使用缓存?

  • 经常查询并且不经常改变的数据。

MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。 为了使它更加强大而且易于配置,我们对 MyBatis 3 中的缓存实现进行了许多改进。
默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。mybatis 也提供了对缓存的支持, 分为一级缓存二级缓存。 但是在默认的情况下, 只开启一级缓存(一级缓存是对同一个 SqlSession 而言的)。
注:下面的测试案例,idea创建Maven项目,导入相关依赖均不作介绍。
一、一级缓存。
一级缓存是SqlSession级别的缓存(默认是支持一级缓存,不需要在配置文件中配置一级缓存),在操作数据库时,每个SqlSession类的实例对象中有一个数据结构(HashMap)可以用来存储缓存数据,不同的SqlSession类的实例对象缓存的数据区域(HashMap)是互不影响的。当在同一个SqlSession中执行两次相同的sql语句时,第一次执行完毕会将数据写到内存中,第二次查询不执行sql直接从内存中获取。
下面以一个从user表中查找用户为例。
数据库接口:UserMapper.java

 //根据id查询用户
    User queryUserById(@Param("id") int id);

pojo类:User.java 省略了对应的set、get方法。

public class User {
    private int id;
    private String username;
    private String password;
}
    @Test
    public void queryUserByIdTest(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user1 = mapper.queryUserById(1);
        System.out.println(user1);
        System.out.println("*******************************************");
        User user2 = mapper.queryUserById(1);
        System.out.println(user2);
        System.out.println(user1==user2);
        sqlSession.close();
    }

在上面的代码中, 进行了两次查询, 使用相同的 SqlSession。
启动项目:
在这里插入图片描述
从上面的日志输出的结果看出,我们可以得出结论:两次的查询情况是不同的:
第一次查询发送了 SQL 语句, 后返回了结果;
第二次查询没有发送 SQL 语句, 直接从内存中获取了结果。
而且两次结果输入一致, 同时断言两个对象相同。

缓存失效的几种情况:

  • 查询不同的内容。
    @Test
    public void queryUserByIdTest(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user1 = mapper.queryUserById(1);
        System.out.println(user1);
        System.out.println("*******************************************");
        User user2 = mapper.queryUserById(2);
        System.out.println(user2);
        System.out.println(user1==user2);
        sqlSession.close();
    }
  • 增删改操作,可能会改变原来的数据,导致刷新缓存。
    @Test
    public void queryUserByIdTest(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user1 = mapper.queryUserById(1);
        System.out.println(user1);
        mapper.updateUser(new User(2,"zhangsan","1234"));
        System.out.println("*******************************************");
        User user2 = mapper.queryUserById(1);
        System.out.println(user2);
        System.out.println(user1==user2);
        sqlSession.close();
    }

在这里插入图片描述

  • 查询不同的Mapper.xml
  • 手动的清除缓存。
  sqlSession.clearCache(); 
    @Test
    public void queryUserByIdTest(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user1 = mapper.queryUserById(1);
        System.out.println(user1);
        sqlSession.clearCache(); //手动清理缓存
        System.out.println("*******************************************");
        User user2 = mapper.queryUserById(1);
        System.out.println(user2);
        System.out.println(user1==user2);
        sqlSession.close();
    }

在这里插入图片描述
二、二级缓存。
二级缓存也叫全局缓存。
工作机制

  • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
  • 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据会被保存到二级缓存中;
  • 新的会话查询信息,就可以从二级缓存中获取内容;
  • 不同的mapper查出的数据会放在自己对应的缓存(map)中;

首先在Mybatis的核心配置文件中设置:

   <!--显式的开启全局缓存-->
        <setting name="cacheEnabled" value="true"/>

然后再Mapper中开启二级缓存:

 <!--在当前Mapper.xml中使用二级缓存-->
    <cache/>

pojo实现序列化接口:

public class User implements Serializable {
    private int id;
    private String username;
    private String password;
}
    //二级缓存的使用
    @Test
    public void queryUserByIdTest2(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        SqlSession sqlSession2 = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user=mapper.queryUserById(1);
        System.out.println(user);
        sqlSession.close();
        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
        User user2=mapper2.queryUserById(1);
        System.out.println(user2);
        sqlSession2.close();
    }

测试结果:
在这里插入图片描述

  • 只要开启了二级缓存,在同一个Mapper下就有效
  • 所有的数据都会先放在一级缓存中;
  • 只有当会话提交,或者关闭的时候,才会提交到二级缓存中!

参考文章:
https://blog.csdn.net/weixin_37139197/article/details/82908377
https://mybatis.org/mybatis-3/zh/sqlmap-xml.html

发布了105 篇原创文章 · 获赞 30 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43759352/article/details/104682016