大家好,又见面了,我是你们的朋友全栈君。
应用场景: 对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度,业务场景比如:耗时较高的统计分析sql、电话账单查询sql等。 实现方法如下:通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定。
局限性: mybatis二级缓存对细粒度的数据级别的缓存实现不好,比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息, 此时如果使用mybatis的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper为单位划分, 当一个商品信息变化会将所有商品信息的缓存数据全部清空。解决此类问题需要在业务层根据需求对数据有针对性缓存。 缓存都是实现了Cache这个接口…..
如何开启 二级缓存,步骤如下: 1.导入ehcache相关jar包 (ehcache: 缓存插件,插件:就是对现有应用软件功能的一个扩展)
代码语言:javascript复制 ehcache-core-2.6.5.jar
mybatis-ehcache-1.1.0.jar
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.6.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.1.0</version>
</dependency>
2,开启mybatis的二级缓存
代码语言:javascript复制在mybatis核心配置文件mybatis-config.xml中加入
<settings>
<!-- 开启二级缓存 -->
<setting name="cacheEnabled" value="true" />
</settings>
3.在classpath下加入ehcache.xml文件
代码语言:javascript复制<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
<!--
默认缓存配置,
以下属性是必须的:
name :cache的标识符,在一个CacheManager中必须唯一。
maxElementsInMemory : 在内存中缓存的element的最大数目。
maxElementsOnDisk : 在磁盘上缓存的element的最大数目。
eternal : 设定缓存的elements是否有有效期。如果为true,timeouts属性被忽略。
overflowToDisk : 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上。
以下属性是可选的:
timeToIdleSeconds : 缓存element在过期前的空闲时间。
timeToLiveSeconds : 缓存element的有效生命期。
diskPersistent : 在VM重启的时候是否持久化磁盘缓存,默认是false。
diskExpiryThreadIntervalSeconds : 磁盘缓存的清理线程运行间隔,默认是120秒.
memoryStoreEvictionPolicy : 当内存缓存达到最大,有新的element加入的时候,
移除缓存中element的策略。默认是LRU,可选的有LFU和FIFO
-->
</ehcache>
属性说明: diskStore:指定数据在磁盘中的存储位置。 defaultCache:当借助CacheManager.add(“demoCache”)创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略 以下属性是必须的: maxElementsInMemory – 在内存中缓存的element的最大数目 maxElementsOnDisk – 在磁盘上缓存的element的最大数目,若是0表示无穷大 eternal – 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断 overflowToDisk – 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上 以下属性是可选的: timeToIdleSeconds – 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大 timeToLiveSeconds – 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大 diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区. diskPersistent – 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。 diskExpiryThreadIntervalSeconds – 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作 memoryStoreEvictionPolicy – 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)
4.在UserMapper.xml中开启二缓存,UserMapper.xml下的sql执行完成会存储到它的缓存区域(HashMap)
代码语言:javascript复制 <cache type="org.mybatis.caches.ehcache.EhcacheCache">
<!-- timeToLiveSeconds 缓存自创建日期起至失效时的间隔时间 -->
<property name="timeToIdleSeconds" value="3600" />
<!-- timeToIdleSeconds 缓存创建以后,最后一次访问缓存的日期至失效之时的时间间隔 -->
<property name="timeToLiveSeconds" value="3600" />
<!-- 同ehcache参数maxElementsInMemory -->
<property name="maxEntriesLocalHeap" value="1000" />
<!-- 同ehcache参数maxElementsOnDisk -->
<property name="maxEntriesLocalDisk" value="10000000" />
<!-- 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO
(先进先出) -->
<property name="memoryStoreEvictionPolicy" value="LRU" />
</cache>
<!--mybatis ehcache缓存配置 -->
<!-- 以下两个<cache>标签二选一,第一个可以输出日志,第二个不输出日志 -->
<cache type="org.mybatis.caches.ehcache.LoggingEhcache" />
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
测试:需求获取员工表所有记录数(测试二级缓存), 执行一次查询后,关闭session;然后获得一个全新的Session,再执行查询,若此时控制台未输出sql语句,且磁盘相应缓存目录下有缓存文件产生,证明二级缓存发挥了作用。 sql映射文件中:
代码语言:javascript复制<cache type="org.mybatis.caches.ehcache.EhcacheCache">
<!-- timeToLiveSeconds 缓存自创建日期起至失效时的间隔时间 -->
<property name="timeToIdleSeconds" value="3600" />
<!-- timeToIdleSeconds 缓存创建以后,最后一次访问缓存的日期至失效之时的时间间隔 -->
<property name="timeToLiveSeconds" value="3600" />
<!-- 同ehcache参数maxElementsInMemory -->
<property name="maxEntriesLocalHeap" value="1000" />
<!-- 同ehcache参数maxElementsOnDisk -->
<property name="maxEntriesLocalDisk" value="10000000" />
<!-- 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO
(先进先出) -->
<property name="memoryStoreEvictionPolicy" value="LRU" />
</cache>
dao实现类中:
代码语言:javascript复制 @Override
public List<Person> selectAll() {
//步骤:
//通过工具类获得SqlSession的实例
SqlSession sqlSession = MyBatisUtil.getSqlSessionInstance();
List<Person> persons = sqlSession.selectList("com.uplooking.dao.PersonDao.selectAll");
System.out.println("第一次查询到的员工数是:" persons);
//关闭sqlSession(让一级缓存失效)
MyBatisUtil.releaseResource(sqlSession);
//执行完下面的代码行,控制台若没有sql语句输出,证明结果来自于二级缓存,而不是重新查询的数据库。
sqlSession = MyBatisUtil.getSqlSessionInstance();
persons = sqlSession.selectList("com.uplooking.dao.PersonDao.selectAll");
System.out.println("第二次查询到的员工数是:" persons);
//释放资源
MyBatisUtil.releaseResource(sqlSession);
return persons;
}
建议:放弃二级缓存,在业务层使用可控制的缓存代替更好。 <select id=”selectUserRoles” resultType=”UserRoleVO”> select * from user_role a,role b where a.roleid = b.roleid and a.userid = #{userid} </select> 像上面这个查询,你会写到那个xml中呢?? 不管是写到RoleMapper.xml还是UserRoleMapper.xml,或者是一个独立的XxxMapper.xml中。如果使用了二级缓存,都会导致上面这个查询结果可能不正确。 如果你正好修改了这个用户的角色,上面这个查询使用缓存的时候结果就是错的。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/191453.html原文链接:https://javaforall.cn