高级java每日一道面试题-2024年9月19日-框架篇[Mybatis篇]-说一下mybatis的一级缓存和二级缓存?
如果有遗漏,评论区告诉我进行补充
面试官: 说一下mybatis的一级缓存和二级缓存?
我回答:
在MyBatis中,缓存机制是一个重要的特性,它可以帮助减少数据库的访问次数,从而提高应用的性能。MyBatis提供了两级缓存:一级缓存(也称为Session级缓存)和二级缓存(也称为跨Session缓存或映射器级别的缓存)。下面将详细解释这两种缓存机制。
一级缓存(Session级缓存)
概述
- 一级缓存是默认开启的,它是基于
SqlSession
级别的缓存。 - 每个
SqlSession
对象都有自己的缓存空间,这个缓存是私有的,不同SqlSession
之间的缓存互不影响。
工作原理
- 当一个查询被执行时,MyBatis首先会检查一级缓存中是否存在该查询的结果。
- 如果存在,则直接返回缓存中的结果,避免了对数据库的重复访问。
- 如果不存在,则执行查询并将结果存入一级缓存中,供后续相同查询使用。
缓存失效情况
- 当执行SQL语句进行增删改操作(INSERT、UPDATE、DELETE)时,MyBatis会清空当前SqlSession的一级缓存,因为增删改操作可能会影响到缓存中数据的一致性。
- 当执行不同的SqlSession时,每个SqlSession都有自己独立的一级缓存,它们之间互不影响。
- 手动调用SqlSession的clearCache()方法也会清空一级缓存。
缓存实现
- MyBatis的一级缓存通常使用PerpetualCache(一种简单的基于HashMap的缓存)实现,但也可以配置为使用其他缓存实现,如FIFOCache(先进先出缓存)或LRUCache(最近最少使用缓存)等。
优点
- 提高了查询性能,减少了数据库访问次数。
- 实现简单,默认开启,无需额外配置。
缺点
- 只在同一个
SqlSession
内有效,跨SqlSession
无法共享缓存。 - 更新操作会导致整个缓存被清空,可能会导致缓存命中率降低。
二级缓存(跨Session缓存/全局缓存)
概述
- 二级缓存是基于
namespace
级别的缓存,可以被多个SqlSession
共享。二级缓存是跨SqlSession的,它的作用域是Mapper(映射器)的命名空间。这意味着,同一个Mapper映射的多个SqlSession之间可以共享缓存数据。 - 二级缓存是可选的,需要显式地开启,并且要确保序列化支持。
工作原理
- 当一个查询被执行时,MyBatis首先会检查二级缓存中是否存在该查询的结果。
- 如果存在,则直接返回缓存中的结果。
- 如果不存在,则执行查询并将结果存入二级缓存中,供后续相同查询使用。
配置步骤
-
开启二级缓存:
- 在
mybatis-config.xml
文件中设置<setting name="cacheEnabled" value="true"/>
。 - 在映射文件(如
Mapper.xml
)中添加<cache/>
标签来启用二级缓存。
- 在
-
序列化支持:
- 确保实体类实现了
Serializable
接口,以便于对象可以被序列化并存储在缓存中。
- 确保实体类实现了
-
控制缓存行为:
- 可以通过
<cache>
标签的属性来控制缓存的行为,例如设置缓存过期时间、读写策略,eviction(回收策略)、flushInterval(刷新间隔)、size(引用数目)等。 - 也可以通过
<select>
、<insert>
、<update>
、<delete>
标签上的useCache
和flushCache
属性来控制特定语句是否使用缓存以及是否刷新缓存。
- 可以通过
缓存失效情况
- 与一级缓存类似,执行增删改操作也会使二级缓存失效。
- 当SqlSession关闭或提交时,MyBatis会尝试将二级缓存中的数据写回到数据库(这取决于配置的flushCache属性),并清空当前SqlSession中的一级缓存。
- 不同的Mapper之间,如果开启了二级缓存,它们之间也可以共享缓存数据,但前提是这些Mapper的缓存配置要兼容。
- 调用了
clearCache()
方法手动清空缓存。 - 根据配置的缓存策略,如过期时间到达时,缓存会被自动清空。
注意事项
- 二级缓存中的数据是跨SqlSession的,因此必须保证缓存数据的序列化(因为缓存数据可能存储在磁盘或其他介质上)。
- 二级缓存可能会引起脏读等问题,因为缓存的数据可能不是最新的(尽管有刷新机制,但依然存在风险)。
优点
- 可以在多个
SqlSession
之间共享缓存,提高了整体应用的性能。 - 提供了更多的配置选项,可以根据需求灵活调整缓存行为。
缺点
- 需要显式配置,增加了开发复杂度。
- 更新操作会导致整个
namespace
下的缓存被清空,可能会影响缓存命中率。 - 对象必须实现
Serializable
接口,增加了序列化的开销。
总结
- 一级缓存是默认开启的,基于
SqlSession
级别的缓存,适用于单个SqlSession
内的多次查询。 - 二级缓存是基于
namespace
级别的缓存,需要显式开启,可以在多个SqlSession
之间共享,适用于跨SqlSession
的查询。
在面试中,能够清晰地解释MyBatis的一级缓存和二级缓存的工作原理、配置方式以及各自的优缺点,将有助于展示你对MyBatis框架的理解和技术深度。此外,实际项目经验也是面试官非常看重的部分,因此准备好相关的项目案例来说明你的实践经历也是非常有帮助的。