Mybatis的一级缓存与二级缓存

每天早上七点三十,准时推送干货

我们都知道缓存,缓存的作用也都是非常的明显,为了减轻数据库的压力,有些时候查询数据的时候,会把数据存入到缓存中,等接下来相同的请求查询数据时,直接从缓存中获取数据,不用再去访问数据库了,而合理使用缓存是优化中最常见的,避免频繁操作数据库,减轻数据库的压力,同时提高系统性能。

Mybatis 的一级缓存

什么是Mybatis的一级缓存

一级缓存是 SqlSession 级别的缓存。在操作数据库时需要构造 SqlSession 对象,在对象中有一个数据结构用于存储缓存数据。

不同的 SqlSession 之间的缓存数据区域是互相不影响的。也就是他只能作用在同一个 SqlSession 中,不同的 SqlSession 中的缓存是互相不能读取的。

一级缓存的工作原理图解:

用户发起查询请求,查找某条数据,SqlSession 先去缓存中查找,是否有该数据,如果有,读取;

如果没有,从数据库中查询,并将查询到的数据放入一级缓存区域,供下次查找使用。

SqlSession 执行 commit,即增删改操作时会清空缓存。

那么清空的意义在哪,了不起都不用多说了吧,这清空的意义就是要保证我们读取的数据一定是准确的,如果你执行了增删改的操作之后,进行了 commit 之后,我们不做清空操作,那么查询的数据,肯定不是最新的,也就是会出现脏读的情况了。

如果不清空的情况下,就会有这种情况,某一件商品,库存有10件,这个时候我们查看的时候,发现库存10件,然后查询之后,写入了缓存,而接下来有人下单,一口气购买了10件,数据没了,如果我们不清空缓存中的内容,那么接下来我们还是从缓存中去取数的话,取出来的数据10就是一个错误的数据了。

Mybatis 的二级缓存

Mybatis的二级缓存是什么?

二级缓存是 mapper 级别的缓存,多个 SqlSession 去操作同一个 Mappersql 语句,多个 SqlSession可以共用二级缓存,二级缓存是跨 SqlSession 的。

二级缓存原理图:

UserMapper 有一个二级缓存区域(按 namespace 划分),每个 mapper 也有自己的二级缓存区域(按 namespace 分)。

每一个 namespacemapper 都有一个二级缓存区域,如果相同两个 mappernamespace ,这两个 mapper 执行 sql 查询到数据将存在相同的二级缓存区域中。

如何开启二级缓存

如果你使用了 Mybatis 的配置文件,那么就得增加配置为:

<settings>
<!-- 开启二级缓存 -->
<setting name="cacheEnabled" value="true"/>
</settings>

如果你使用的是 yml 去配置的话,那么就得在 configuration 下去开启:

configuration:
    cache-enabled: true

我们看一段测试代码:

@Test
public void testCache2() throws Exception {
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
User user1 = userMapper1.findUserById(1);
System.out.println(user1);
sqlSession1.close();
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
User user2 = userMapper2.findUserById(1);
System.out.println(user2);
sqlSession2.close();
}

日志打印:

DEBUG [main] - Cache Hit Ratio [com.iot.mybatis.mapper.UserMapper]: 0.0
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 103887628.
DEBUG [main] - Setting autocommit to false on JDBC Connection
[com.mysql.jdbc.JDBC4Connection@631330c]
DEBUG [main] - ==> Preparing: SELECT * FROM user WHERE id=?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <== Total: 1
User [id=1, username=张三, sex=1, birthday=null, address=null]
DEBUG [main] - Resetting autocommit to true on JDBC Connection
[com.mysql.jdbc.JDBC4Connection@631330c]
DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]
DEBUG [main] - Returned connection 103887628 to pool.
DEBUG [main] - Cache Hit Ratio [com.iot.mybatis.mapper.UserMapper]: 0.5
User [id=1, username=张三, sex=1, birthday=null, address=null]

我们可以从打印的信息看出,两个 SqlSession,去查询同一条数据,只发起一次 select 查询语句,第二次直接从 Cache 中读取。

前面我们说到,SpringMyBatis 整合时, 每次查询之后都要进行关闭 SqlSession,关闭之后数据被清空。所以 spring 整合之后,如果没有事务,一级缓存是没有意义的。

那么如果开启二级缓存,关闭 sqlsession 后,会把该 sqlsession 一级缓存中的数据添加到 namespace 的二级缓存中。这样,缓存在 sqlsession 关闭之后依然存在。

二级缓存的使用

1. 只能在一个命名空间下使用二级缓存

由于二级缓存中的数据是基于 namespace 的,即不同 namespace 中的数据互不干扰。在多个 namespace 中存在对同一个表的操作,那么这多个 namespace 中的数据可能就会出现不一致现象。

2. 在单表上使用二级缓存

如果一个表与其它表有关联关系,那么就非常有可能存在多个 namespace 对同一数据的操作。而不同 namespace 中的数据相互干扰,所以就有可能出现多个 namespace 中的数据不一致现象。

3. 查询多于修改时使用二级缓存

在查询操作远远多于增删改操作的情况下可以使用二级缓存。因为任何增删改操作都将刷新二级缓 存,对二级缓存的频繁刷新将降低系统性能。





号外!号外!

Java 极客技术微信群中有很多优秀的小伙伴在讨论技术,偶尔还有不定期的资料分享和红包发放!如果你想提升自己,并且想和优秀的人一起进步,感兴趣的朋友,可以在下方公众号后台回复:加群

喜欢就分享
认同就点赞

支持就在看

一键四连,你的offer也四连



相关推荐

  • 丰富的模板与插件,构建你心中的理想站点
  • 陈怡然力荐《关于我博士毕业的这件小事》,Waymo研究员2年半心路分享火了
  • 大华股份发布星汉大模型;苹果AI服务器支出明年或达47.5亿美元;英伟达H100成新型债务资产丨AIGC大事日报
  • 净利润暴涨1763%,世界第三大软件公司如何靠AIGC逆风翻盘?
  • 提升时间序列聚类的表现的秘密方法。
  • 语雀停服八小时,P0级事故!故障原因和补偿来了!!
  • SpringBoot 快速实现 api 加密,一个轮子搞定!
  • [开源]一套企业级微服务框架、微服务能力开放平台,功能强大
  • 低风险、高回报,AI+简历修改项目分享
  • 1024 程序员节|100 秒里的小红书技术这一年
  • 30.4K Star开源项目:探索二进制世界的强大十六进制编辑器
  • 思路打开,换个方式解决算力和数据问题
  • Python网页开发神器fac新版本来了
  • 闹大了!淘宝这是什么操作?!
  • 清华新研究解密信息茧房!全新信息动力学理论,登Nature子刊
  • 美国码农疯狂求职,狂投250份简历!揭秘潜规则:网申填完就战胜92%对手
  • 爆火AutoGPT获1200万美元融资,GitHub已有151k星
  • LeCun和xAI联创对呛,GPT-4重大推理缺陷无解?网友:人类也是「随机鹦鹉」
  • 明年对标GPT-4!星火3.0高能进化,给AI注入灵魂,林黛玉马斯克多种人设可定制
  • 1024 程序员节引爆星城,180+ 位大咖谈 AIGC、开源,开启未来编程范式!