Mybatis提供查询缓存,用于减轻数据库压力,提高数据库性能。查询缓存分为一级缓存和二级缓存。
一级缓存是SqlSession级别的缓存。在操作数据库时需要SqlSession对象,在对象中有一个数据结构(hasmap)用于存储缓存数据。不同的SqlSession之间的缓存数据区域(hashmap)是互不影响的。
二级缓存是mapper级别的缓存,多个SqlSession去操作同一个mapper的Sql语句,多个SqlSession可以共有一个二级缓存,也就可以说二级缓存是跨SqlSession的。
一级缓存:
Mybatis默认支持一级缓存;不需要再配置文件中配置。
工作原理:
第一次发送查询数据信息,先去缓存中查找是否存在该信息,若无,则从数据库中查询。
若SqlSession去执行增、改、删操作,则情况SqlSession中的一级缓存,目的是为了让缓存中存储的是最新的数据信息,避免脏读。
第二次发起同样动作的数据查询,先去缓存中查找是否存在该信息,若存在,则直接获取。
二级缓存:
Mybatis在使用二级缓存时需要开启二级缓存。
Mybatis的二级缓存是mapper的范围级别,除了在SqlMapConfig.xml中配置开启二级缓存,还要在具体的mapper.xml中开启二级缓存。
<!-- SqlMapConfig.xml中配置 开启二级缓存 --> <settings> <setting name="cacheEnabled" value="true"/> </settings> <!-- mapper.xml中配置开启二级缓存 配置的是本mapper的二级缓存 --> <cache/>
每一个mapper都有一个二级缓存区域,缓存区域是按照namespace区分。每个namespace的mapper都有一个二级缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql查询到的数据将存储到相同的二级缓存区域中。
调用pojo类实现序列化接口:
实现序列化接口是为了将缓存数据去执行反序列化操作,因为二级缓存数据存储介质多种多样,不一定在内存。
禁用二级缓存:
在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认为true。即使用二级缓存。
<select id="xxx" resultMap="xxx" useCache="false">
刷新缓存:
就是清空缓存。在mapper的同一个namespace中,若有其它增、改、删操作数据后需要刷新缓存,若不执行刷新缓存会出现脏读。
设置statement配置中的flushCache=true属性,默认情况下true。即刷新缓存,若改为false则不会刷新。使用缓存时,若手动修改数据库中的查询数据就会出现脏读。
<select id="xxx" parameterType="xx" flushCache="true">
一般情况下完成增、删、改的commit()操作都需要刷新缓存。
Mybatis整合ehcache:
系统为了提高系统并发、性能,一般对系统进行分布式部署(集群部署方式)。不使用分布式缓存,缓存的数据在各各服务器单独存储,不方便系统开发,所以要使用分布式缓存对缓存数据进行集中管理。
Mybatis无法实现分布式缓存,故需要和其他分布式缓存框架进行整合。
整合方法:
Mybatis提供了Cache接口,若要实现自己的缓存逻辑,实现Cache接口开发即可。Mybatis提供了一个默认支持的Cache接口实现类PerpetualCache。
配置mapper中cache标签中的type为ehcache的实现类型:
<!-- type:指定cache接口的实现类的类型,Mybatis默认使用PerpetualCache要和ehcache整合,需要配置type为ehcache实现cache接口的类型。 --> <cache type=""/>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"> <diskStore path="java.io.tmpdir"/> <!-- 默认缓存配置。 创建方式:CacheManager.add(String cacheName) --> <!-- name:缓存名称。 maxElementsInMemory:缓存最大个数。 eternal:对象是否永久有效,一但设置了,timeout将不起作用。 timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。 仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。 timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。 最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。 overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。 diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。 maxElementsOnDisk:硬盘最大缓存个数。 diskPersistent:是否缓存虚拟机重启期数据,在重启虚拟机之间,磁盘存储是否持久。默认值为false diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。 memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。 默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。 clearOnFlush:内存数量最大时是否清除。 --> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" maxElementsOnDisk="10000000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" /> </ehcache>
应用场景:
对于访问量大且实时性不高的数据和查询非常耗时的数据来使用二级缓存。
实现方法:
通过设置刷新间隔时间,有mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval。
二级缓存局限性:
mybatis二级缓存对细粒度的数据级别的缓存实现不好。因为mapper中存储的是所有的缓存,只要有一个执行commit(),就会全部清空。