那天,我去面试一家中型互联网公司,面试官是个看起来三十多岁的大哥,一开口就直奔主题:“你说说 MyBatis 的一级缓存和二级缓存吧。”
我笑了笑,心里想着:“老哥,这不就是送分题嘛!”结果这一聊,我居然整整说了半个小时……
缓存,听起来就不一般
先别急着上技术,咱们先聊个生活场景。
有一天我和老婆在家看剧,我问她:“你记得这集上次看到哪儿了吗?”
她翻翻遥控器记录,说:“哦,历史记录里有,继续播放就好。”
我灵光一闪,跟她解释:“老婆你知道嘛,这跟我们 MyBatis 里的缓存原理差不多!我们项目里,查询结果也能存一份到缓存里,下次查一样的,就不用再走数据库啦~”
她翻了个白眼,说:“能不能别什么都扯到 MyBatis 上?”
嘿嘿,这不就是程序员嘛。
什么是一级缓存?(Session级别)
我们先从简单的开始。
一级缓存就是 SqlSession 级别的缓存,默认开启。也就是说,只要你在同一个 SqlSession 中重复执行同一条查询语句,MyBatis 就不会再去数据库查了,直接从缓存里拿!
举个例子:

这两次查询,其实只有第一次是真正查数据库,第二次是从缓存拿的,效率嗖嗖的。
但注意!只要 SqlSession 一关闭,缓存也就没了。就像你用微信小程序买菜,界面关了,记录就清了(除非你加了个本地存储)。
哪些操作会清除一级缓存?
这个地方要格外注意,有些“动静大”的操作会让缓存失效:
执行了 update、insert、delete 这些修改操作;
使用了不同的 SqlSession;
手动调用 sqlSession.clearCache();
查询参数不同或 statementId 不一样;
显式使用 flushCache=true 的查询;
也就是说,只要你“动”了数据,MyBatis 就小心翼翼地把缓存清掉,避免你查到老数据。
啥是二级缓存?(Mapper级别)
一级缓存说完了,再来看稍微高级点的二级缓存。
这个缓存的作用范围比一级缓存大多了,是 mapper 级别的缓存,也就是多个 SqlSession 之间可以共享!
但是它默认是 关闭的,得你自己手动打开:

有了这个 <cache/>,你 Mapper 层的查询结果就能存到二级缓存里,下次别的 SqlSession 调用也能用。
重点来了:
二级缓存的本质,是通过把查询结果 序列化之后放到某个公共区域里(通常是内存,也可以接入 ehcache、redis 等),然后别的 SqlSession 再从这个地方取数据。
这个过程比一级缓存复杂一些,也更适合做读多写少的查询。
那么,二级缓存什么时候生效?
Mapper 配置了 <cache/>
查询语句没有设置 useCache=”false”
SqlSession 提交或者关闭后,缓存才会真正写入
所查询的对象是可序列化的(实现 Serializable 接口)
没有执行更新操作清掉缓存
是不是感觉它像个“公共图书馆”?大家都可以来借书,但管理员(MyBatis)会在你还书(提交事务)之后才把书放上架。
一级 vs 二级,你选谁?
如果你问我:“项目里该怎么选?”
我的建议是:一级缓存默认开着,放心用;二级缓存慎用,特别是要评估数据一致性的问题。
我们项目之前就踩过坑。某个查询本来是用来查用户积分的,我们把它放到了二级缓存。结果一个用户刚刚下单、积分就变了,可缓存里还是老值。客户投诉说积分对不上,我们才发现二级缓存压根没更新。
后来我们干脆把那块的二级缓存关了,重要数据咱还是查最新的稳妥。
面试官的追问三连击
面试官听我巴拉巴拉讲完,点了点头,来了一波灵魂拷问:
“你说缓存清空了,那是谁来判断重复查询的?”
“如果我用了注解方式查询,还能走缓存吗?”
“那缓存穿透怎么办?”
我赶紧继续上分:
MyBatis 会基于 MappedStatement id + 参数值 生成一个缓存 key,用这个 key 去判断是否命中缓存;
注解方式其实底层也是 MappedStatement,会有缓存,但得看你怎么配置;
缓存穿透的话,建议加缓存空值策略或者做布隆过滤器。
面试官点点头:“你这块讲得还挺清楚。”
我心想:嘿,这不全靠之前项目踩坑踩多了嘛!
总结回顾:记住这几个关键词
面试说得好,不如记得牢。下面这张口诀表,送你——

顺口溜来一段:
一级缓存随手用,SqlSession 别乱动;
二级缓存需配置,读多写少别出气;
修改操作会清除,参数不同查不出;
多练项目带理解,面试才不怕被虐!
END
缓存不是银弹,也不是洪水猛兽,关键是你要理解它背后的设计理念和使用场景。在系统中合理使用缓存,能极大提高性能;但若处理不好,也会引发数据一致性的大坑。
如果你也准备跳槽、准备社招面试,记得这一题别翻车哦!
我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎已关注我的微信公众号“软件求生”,获取更多技术干货!
我们下期见!












暂无评论内容