Mybatis一级缓存、二级缓存详讲

 

Mybatis 一级缓存、二级缓存

作者 : Stanley 罗昊

转载请注明出处和署名,谢谢!

查询缓存

首先,我们先看一下这个标题“查询缓存”,那就说明跟增、删、改是没有任何关联的只有在查询时,才会遇到缓存,增删改不涉及!

查询缓存目前 Mybatis 中提供了两个,分别是:一级缓存、二级缓存;

一级缓存

先说一下一级缓存的范围:同一个 SqlSession 对象,也就说,我们是同一个 SqlSession 对象,又要进行同样的查询操作,那么,我们就可以去缓存中获取;

所以,SqlSession 的缓存,是属于一级缓存;

那,又有什么用呢?

比如,我们现在数据库中有两条数据,分别是张三跟李四;

我现在呢,要根据 name 来查询张三这个人,首先说明一点,这是第一次去根据 name 来查询张三,这个时候呢,我们就会去访问数据库,去获取 name 是张三的数据,拿到张三后,它会把张三又放进了 Sqlssion 对象中去了,Sqlssion 对象存在内存中;

也就是说,我们第一次查完后,我们会将张三这个数据从数据库中获取一下,获取后放到缓存里面,此时的缓存就在内存里面,具体的来说,它就在 Sqlsession 对象里面;

上述操作如下图:

 

如果,再有一次或再有 N 次来查询这个张三,我就不需要去访问数据库了,因为我在缓存里面已经有了,如果你再要拿这个张三,直接直接从缓存里面去拿;

因此呢,我们可以发现,缓存可以减少数据库的访问

 

我们都知道,数据库的打开与关闭均比较费性能,所以,我们就不需要从数据库中拿了,直接从缓存中去获取就完事了,意思就是可以提高性能;

SqlSession 对象清空机制

只要执行你 commit(提交)这个方法,那么就会直接将 SqlSession 对象全部清空掉,一旦执行 commit,就会清理我们的缓存对象;

上述如下图:

首先,这些操作,我们不需要去手动的去编写,我们仅需知道并了解即可,因为 Mybatis 默认了就开启了一级缓存;

总结:

如果用相同的 SqlSession 对象查询相同的数据,则只会在第一次查询时发送 Sql 语句,并将这个查询的结果放入到 Sqlsession 中(作为缓存存在);

后续再次查询该同意的对象时,则直接从缓存中查询该对象即可(即省略了数据库的访问)

二级缓存

首先,这个 Mybatis 自带二级缓存;

也有三方提供的二级缓存;

Mybatis 觉得缓存很重要,所以就自带了一个缓存,但是,Mybatis 必定不是搞缓存的,搞数据的,但是第三方公司给你提供了一些缓存,因为你 mybatis 做缓存这块儿不是专业的;

我们可以回顾一下,一级缓存是同一个 Sqlsession 对象,那么二级缓存呢?

二级缓存是同一个在同一个 namespace 生成的 mapper 对象,重点是这个 namespace; 

也就是说,哪怕你生成了许多对象,只要你这个对象来自同一个 namespace,它们就会共享同一个缓存;

什么是 namespace,我在这里就不强调了,因为这个是 mybatis 入门必学的;

简单点来说:

只要产生的 xxxMapper 对象来自于同一个 namespace, 则,这个对象共享二级缓存;

二级缓存的这个共享范围,是同一个 namespace 产生的 xxxMapper 对象;

开启缓存很简单,如果你是 boot 项目的话,直接在你需要开启的 mapper.xml 中加上一句话,来表示本 namespace 开启了二级缓存:

<cache/>;

如果是 ssm 框架的话,需要在 conf.xml 中添加一些配置:

在这里,顺便提一下,mybatis 的二级缓存是属于序列化,序列化的意思就是从内存中的数据传到硬盘中,这个过程就是序列化;

反序列化意思就是相反而已;

也就是说,mybatis 的二级缓存,实际上就是将数据放进了硬盘文件中去了;

实现序列化接口

如果你要使用 mybatis 的二级缓存,那么你除了要在你需要缓存的 mappe.xml 中开启以外,你还需要实现序列化的接口,在你需要使用二级缓存的实体类中;

去实现这个 Serializable(序列化)接口即可;

 现在呢,你仅仅的将 Student 类给序列化了,Student 有父类、级联属性,它们是不会跟着被序列化的,所以光这些是不够的;

其实很简单,如果 Student 需要序列化,但是这个类中还有其他类的属性,仅需将其他类也序列化即可!

比如学生类中继承了父类,那么父类也需要实现 Serializable 这个接口进行序列化;

缓存时机

该序列化也序列化了,也已经在你需要进行缓存的 mapper.xml 文件中也开启缓存了,但是如果你使用原生的 SqlsessionFacotry(SSM\SpringBoot 除外因为是集成好的不需要写底层)去写的时候会发现,缓存并没有起效,而是关闭 Session(session.close())才生效了;

这个其实就是 mybatis 的一个机制,其实很好理解;

比如,我现在去查询张三,获取张三数据之后我们需要经过序列化然后存贮到硬盘上,上面我也说过了,mybatis 的二级缓存实际上就是将数据保存到硬盘上的某个文件中了,照这样,每来一个新的对象,比如张三存进来了,李四也需要存,王五也需要,如果是存储到硬盘上,那么就会用到 IO 技术,众所周知,IO 也是比较费性能,所以这个机制就是当你关闭 session 的时候,我们把这些张三、李四、王五这些数据一块儿保存到硬盘上,而不是来一个保存一个这样 IO 也受不了,所以就存在这样的机制;