【Mybatis】查询缓存

查询缓存:
Mybatis是一个持久层框架,经常访问物理数据库,为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能。缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据。
Mybatis有一级和二级缓存

这里写图片描述

一级缓存:
一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
工作原理:
这里写图片描述
第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息。
得到用户信息,将用户信息存储到一级缓存中。

如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。

第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。
一级缓存组织结构:
这里写图片描述
Executor接口的实现类BaseExecutor中拥有一个Cache接口的实现类PerpetualCache,则对于BaseExecutor对象而言,它将使用PerpetualCache对象维护缓存。

综上,SqlSession对象、Executor对象、Cache对象之间的关系如下图所示:这里写图片描述
由于Session级别的一级缓存实际上就是使用PerpetualCache维护的,
实现原理其实很简单,其内部就是通过一个简单的HashMap k,v

二级缓存:

这里写图片描述
首先开启mybatis的二级缓存。

sqlSession1去查询用户id为1的用户信息,查询到用户信息会将查询数据存储到二级缓存中。

如果SqlSession3去执行相同 mapper下sql,执行commit提交,清空该 mapper下的二级缓存区域的数据。

sqlSession2去查询用户id为1的用户信息,去缓存中找是否存在数据,如果存在直接从缓存中取出数据。
区别:
二级缓存与一级缓存区别,二级缓存的范围更大,多个sqlSession可以共享一个UserMapper的二级缓存区域。
UserMapper有一个二级缓存区域(按namespace分) ,其它mapper也有自己的二级缓存区域(按namespace分)。
每一个namespace的mapper都有一个二缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同的二级缓存区域中。

开启二级缓存主要有三个步骤。
1开启总的缓存配置。
在核心配置文件SqlMapConfig.xml中加入

<setting name="cacheEnabled" value="true"/>

2开始具体某空间下的缓存配置。

<mappernamespace="cn.itcast.mybatis.UserMapper">
<!--开启本mapper的namespace下的二级缓存-->
<cache/>

3序列化。(用于多种介质下存储)
调用pojo类实现序列化接口

这里写图片描述

为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一样在内存。

值得注意的是:
涉及缓存,则一定涉及数据的一致性问题。在这里也是,在mapper的同一个namespace中,如果有其它insert、update、delete操作数据后需要刷新缓存,如果不执行刷新缓存会出现脏读。
设置statement配置中的flushCache=”true” 属性,默认情况下为true即刷新缓存,如果改成false则不会刷新。使用缓存时如果手动修改数据库表中的查询数据会出现脏读。
如下:

即:一般下执行完commit操作都需要刷新缓存,flushCache=true表示刷新缓存,这样可以避免数据库脏读。

总结:
Mybatis和Hibernate的一级二级缓存的都很相像。一级缓存是session内,二级缓存是session间同一命名空间下。此外,如果做分布式缓存的话,还可以Mybatis与redis,memcached、ehcache等结合。

猜你喜欢

转载自blog.csdn.net/u010176014/article/details/52036332