查询缓存

113 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第30天,点击查看活动详情

一级缓存

MyBatis 中常用的查询缓存分为一级缓存和二级缓存。一级缓存的范围是一个 SqlSession 对象:在同一个 SqlSession 对象中多次执行相同的查询 SQL 语句时,第一次执行完毕就会将数据库的查询结果写到内存(缓存)中,以后如果再次执行该查询时就会直接从内存中读取第一次的查询结果。但是,如果在增、删、改等操作时执行了 commit()方法,那么一级缓存就会被清理(清理是指 “将缓存中的数据全部写入数据库,并且清空已有缓存”),因此下次再次查询时,都会重新从数据库中查询,并将查询后的结果重新写入 SqlSession 对象,如图下图是以 “查询学生信息” 为例的 MyBatis 一级缓存流程图。

图片描述

MyBatis 默认开启一级缓存。并且在使用一级缓存时,当一个 SqlSession 对象关闭后,该 SqlSession 对象中的一级缓存也就随之销毁。

二级缓存

MyBatis 一级缓存的范围是同一个 SqlSession 对象内;而二级缓存是可以被多个 SqlSession 对象共享的,范围是有相同 namespace 值的 SQL 映射文件所生成所有 mapper 对象。与一级缓存相同,当执行增删改的 commit() 方法时,二级缓存也会被清理。值得注意的是,如果两个不同的 SQL 映射文件有相同的 namespace 值,那么这两个 SQL 映射文件生成的两个 mapper 对象共享二级缓存,如下图所示。

图片描述

在使用二级缓存时,只要是使用 namespace 相同的 mapper 对象,就只会在第一次查询时访问数据库并将结果写入二级缓存,以后再次查询时就可以直接从二级缓存中获取。

此外MyBatis 还可以整合 EhcacheOSCacheMEMcache 等由第三方厂商提供的二级缓存解决方案。

实验

第一步:创建maven文件。创建数据库文件(这里以student数据库表为例。)

image.png

student表有字段stuNo,stuName,stuAge,graName。并且插入相关数据。

entity下的student文件就是按照我们数据库文件加入属性和setget方法,并且重写tostring。

studentMapper文件里面有一个studentMapper接口

public interface StudentMapper{
      Student queryStudentByNo(int stuNo);
      …
}

在 SQL 映射文件 StudentMapper.xml 中添加以下代码:

<!-- 根据学号查询学生的信息 -->
    <select id="queryStudentByNo" parameterType="int" resultType="Student">
        select * from student where stuNo=#{stuNo}
    </select>

最后在测试类 TestMyBatis.java 中添加以下方法:

@Test
public void queryStudentByNoTwice() throws IOException{
    …
    StudentMapper studentMapper = session.getMapper(StudentMapper.class);
    //第一次查询学号为32的学生
    Student student1 = studentMapper.queryStudentByNo(32);
    System.out.println(student1);
    //第一次查询学号为32的学生
    Student student2 = studentMapper.queryStudentByNo(32);
    System.out.println(student2);
    …
}

可以发现,虽然本次查询了两次学号为 32 的学生,但实际只向数据库发送了一次查询 SQL 语句,即第二次没有通过 SQL 查询数据库,而是直接从缓存中获取的查询结果。