目录
一、什么是缓存
缓存(cache),即数据交换的缓冲区,当应用程序需要读取数据时,先从数据库中将数据取出,放置在缓冲区中,应用程序从缓冲区中读取数据。
缓存的特点:
- 缓存的优点:缓存可以让从数据库中取出的数据存在内存当中,需要数据的时候直接在内存中去读取,更加快速便捷。
- 缓存的弊端:虽然读取数据的时候是直接在内存当中去拿比较快速,但是这样拿到的数据依旧是原来的旧数据,很可能读到的不是最新的数据。
缓存的术语:
- 命中:需要的数据在缓存中找到称为命中。
- 未命中:需要的数据在缓存中并未找到,需要重新获取,称为未命中。
缓存的适用性:
- 适合使用缓存:
- 经常查询并且不经常改变的
- 数据的正确性对最终结果影响不大的
比如一个公司的介绍,新闻等
- 不适合使用缓存:
- 经常改变的数据
- 数据的正确性对最终结果影响很大的
比如商品的库存,故事的牌价等
二、什么是mybatis缓存
mybatis包含一个非常强大的查询缓存特性,他可以非常方便的定制和配置缓存,通过缓存减少Java Application与数据库的交互次数,从而提升程序的运行效率。
- 默认情况下一级缓存开启(sqlSession级别的缓存,也称本地缓存)
- 二级缓存需要手动开启,映射器级别的缓存,针对不同的namespace的映射器
- 为了提高扩展性,Mybatis定义了缓存接口Cache,我们可以通过实现Cache接口来自定义二级缓存
1.一级缓存
1.1 一级缓存的配置
Mybatis默认开启了一级缓存,一级缓存有两个级别可以设置:session级别和statement级别。默认是session级别
session级别:即在一个Mybatis会话中执行的所有语句都会共享这一个缓存。
statement级别:可以理解为缓存只对当前执行的这一个statement有效。
我们可以在根配置文件下去配置一级缓存:
<setting name="localCacheScope" value="session">
or
<setting name="localCacheScope" value="statement">
1.2 一级缓存的工作流程
- 对于某个Select Statement,根据该Statement生成key;
- 判断在本地缓存(local cache)中,该key是否有对应的数据存在
- 如果命中,则跳过查询数据库,拿到本地的数据,继续往下走。
- 如果没命中,去数据库中查询数据,得到想要的结果
- 将key和查询到的结果作为一个键值对存入本地缓存(local cache)中
- 将查询结果返回
- 判断缓存级别是否为Statement级别,如果是的话,清空本地缓存
1.3一级缓存的实现示例
此处我们在同一个statement下执行两次同样的查询,会在日志里发现第一次查询他执行了查询的sql去数据库里拿了数据,而第二次直接显示了同样的数据结果,第二次便是使用了一级缓存,在缓存中拿了数据。
此处我们在上面的代码后面加一条语句进行验证,结果显示这两个对象指向同一个地址值,说明他们拿到的是同一份数据,即第二次查询结果是在缓存区中拿的。
1.4 一级缓存失效的情况
- >>不同sqlSession对应不同的一级缓存
此处我们创建了两个不同的sqlSession去查询同样的数据,发现缓存失效了,第二次去拿数据的时候依然需要去数据库里拿数据,两次查询拿到的不是同一份结果
- >>同一个sqlSession的查询条件不同
当查询条件不同时,我们所拿到的结果固然也会不同,那么第二次需要的数据也就当然不会在缓存里找到啦!
- >>同一个sqlSession两次查询期间对数据进行了改变,(即增、删、改)
此处我们在两次查询之间做了一个数据库修改,也发现缓存失效了(此处操作可以是对任意的一条或多条数据进行,此处仅仅举例)
- >>同一个sqlSession两次查询期间手动清空了缓存
此处我们在两次查询之间调用了sqlSession的clearCache()方法清空了缓存,缓存自然也就没有了,第二次就要再去数据库里做查询取数据
2.二级缓存
一级缓存中最大的共享范围就是一个sqlSession内部,那么如果多个sqlSession之间需要共享缓存,则要使用二级缓存
2.1 二级缓存的配置
xml配置:
- 在mybatis根配置文件下配置
- 在mybatis的sqlMapper文件下配置
- 在使用操作中配置(select标签中)
注解配置:
- 在mybatis的sqlMapper文件下配置
- 在接口的定义上面直接使用@CacheNamespace 并将blocking设置为true,二级缓存就可以使用了
2.2 二级缓存的工作流程
开启二级缓存后,会使用 CachingExecutor 装饰 Executor ,进入一级缓存的查询流程前,先在CachingExecutor 进行二级缓存的查询。二级缓存开启后,同一个namespace下的所有操作语句,都影响着同一个Cache,即二级缓存被多个SqlSession共享,是一个全局的变量。当开启缓存后,数据的查询执行的流程就是
二级缓存 >> 一级缓存 >> 数据库
工作流程图如下:
2.3 二级缓存总结
- Mybatis 的二级缓存相对于一级缓存来说, 实现了缓存数据的共享,可控性也更强
- 极大可能会出现错误数据,有设计上的缺陷,安全使用的条件比较苛刻
- 分布式环境下,必然会出现读取到错误数据,所以不推荐使用。
三、总结
一级缓存和二级缓存的区别:
范围:一级缓存是sqlSession范围的缓存,缓存只在当前sqlSession中有效;二级缓存是namespace范围的缓存,在同一个sqlMapper映射下有效;
工作流程:一级缓存是先去一级缓存区中查找数据,如果没有再去数据库中查找,找到数据后将数据存入一级缓存区;二级缓存是先去二级缓存区域找数据,没有的话再接着去一级缓存区找数据,如果再没有就去数据库里拿数据,拿到后将数据存入二级缓存区。