mybatis的缓存机制

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis的缓存机制相关的知识,希望对你有一定的参考价值。

在实际项目中,通常对数据库查询的性能要求很高,而MyBatis提供了查询缓存来缓存数据,从而达到提高性能的要求。

MyBatis的查询缓存分为一级缓存和二级缓存。一级缓存是sqlsession级别的缓存,二级缓存是mapper级别的缓存,二级缓存是多个sqlsession共享的。

一级缓存可用性:

一级缓存基于sqlsession,sqlsession又是单线程不共享的。所以只能在本次请求中使用,而如果本次请求有commit操作,比如update、insert、delete,那么缓存就会被刷新。简单来说,只有连续两次执行相同语句,一级缓存才有效果,比如:

select * from tb_user // 执行一次SQL语句

select * from tb_user // 缓存查询

而如果有commit操作

select * from tb_user // 执行一次SQL语句

update tb_user set name = lay where id = 1 // commit 操作,清除了缓存

select * from tb_user // 第二次执行查询SQL

第一种情况,个人认为基本上不太会出现。所以一级缓存在一定程度上来说,基本上没有用

 

二级缓存可用性:

二级缓存是基于mapper的,也就是说,一个mapper会有一个缓存,多个mapper会有多个缓存。并且mapper的缓存是被所有sqlsession共享的,不会因为sqlsession的关闭而清空。

select * from tb_user // 第一个sqlsession进来

select * from tb_user // 第二个sqlsession进来,查询到的是第一个sqlsession的缓存数据

缓存清空的情况

select * from tb_user  // 一个sqlsession进来

update tb_user set name = lay where id = 1 // 执行了commit操作,清空缓存
 
select * from tb_user // 第二个sqlsession进来,得重新执行sql

二级缓存属于一个mapper,也就是当前mapper中如果执行了commit操作,当前mapper才会被清空,那么显而易见的问题就出现了。如果有多表关联查询,commit操作只清空当前的mapper,其它mapper有关联的数据就还是旧的数据,不是出现了数据不一致的情况了吗?

比如:

select * from tb_user // 第一个mapper缓存了数据

select * from tb_class A
left join tb_user B on A.userId = B.id // 第二个mapper缓存了数据,并关联tb_user的数据

update tb_user set name = lay where id = 1 // 第一个mapper中执行了commit操作,清空了第一个mapper的缓存数据

select * from tb_class A
left join tb_user B on A.userId = B.id // 第二个mapper的数据,查询到的是缓存,而且是旧的数据

所以,由于mybatis的二级缓存的机制,多表查询容易出现数据不一致问题,这点需要注意。当然网上也有一些解决方案,不过个人觉得那些方案会增加项目的复杂度,如果项目越来越大mapper的关联越复杂,那些解决方案最终可能导致项目难以理解的问题。

因此,如果对数据的实时性要求不高,查询频率却很高,比如某些排行榜?那么当前mapper使用二级缓存能大大提高性能。如果对数据实时性要求很高,频繁地执行commit操作,那么当前mapper还是不使用二级缓存了。简单来说,根据当前mapper的数据实时性来判断是否使用二级缓存

以上是关于mybatis的缓存机制的主要内容,如果未能解决你的问题,请参考以下文章

MyBatis的缓存机制

聊聊MyBatis缓存机制

MyBatis缓存机制

Mybatis缓存机制

一次读懂mybatis中的缓存机制

推荐学java——MyBatis高级