内容简介:mybatis教程--查询缓存(一级缓存二级缓存和整合ehcache)
查询缓存
1 缓存的意义
将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上 ( 关系型数据库数据文件 ) 查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。
2 mybatis 持久层缓存
mybatis 提供一级缓存和二级缓存
mybatis 一级缓存是一个 SqlSession 级别, sqlsession 只能访问自己的一级缓存的数据,二级缓存是跨 sqlSession ,是 mapper 级别的缓存,对于 mapper 级别的缓存不同的 sqlsession 是可以共享的。
3 一级缓存
3.1 原理
第一次发出一个查询 sql , sql 查询结果写入 sqlsession 的一级缓存中,缓存使用的数据结构是一个 map<key,value>
key : hashcode+sql+sql 输入参数 + 输出参数( sql 的唯一标识)
value :用户信息
,同一个 sqlsession 再次发出相同的 sql ,就从缓存中取不走数据库。如果两次中间出现 commit 操作(修改、添加、删除),本 sqlsession 中的一级缓存区域全部清空,下次再去缓存中查询不到所以要从数据库查询,从数据库查询到再写入缓存。
每次查询都先从缓存中查询:
如果缓存中查询到则将缓存数据直接返回。
如果缓存中查询不到就从数据库查询:
3.2 一级缓存配置
mybatis 默认支持一级缓存不需要配置。
注意: mybatis 和 spring 整合后进行 mapper 代理开发,不支持一级缓存, mybatis 和 spring 整合, spring 按照 mapper 的模板去生成 mapper 代理对象,模板中在最后统一关闭 sqlsession 。
3.3 一级缓存测试
//一级缓存 @Test public void testCache1() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //第一次查询用户id为1的用户 User user = userMapper.findUserById(1); System.out.println(user); //中间修改用户要清空缓存,目的防止查询出脏数据 /*user.setUsername("测试用户2"); userMapper.updateUser(user); sqlSession.commit();*/ //第二次查询用户id为1的用户 User user2 = userMapper.findUserById(1); System.out.println(user2); sqlSession.close(); }
4 二级缓存
4.1 原理
二级缓存的范围是 mapper 级别( mapper 同一个命名空间), mapper 以命名空间为单位创建缓存数据结构,结构是 map<key 、 value> 。
每次查询先看是否开启二级缓存,如果开启从二级缓存的数据结构中取缓存数据,
如果从二级缓存没有取到,再从一级缓存中找,如果一级缓存也没有,从数据库查询。
4.2 mybatis 二级缓存配置
在核心配置文件 SqlMapConfig.xml 中加入
<setting name="cacheEnabled" value="true"/>
要在你的 Mapper 映射文件中添加一行: <cache /> ,表示此 mapper 开启二级缓存。
4.3 查询结果映射的 pojo 序列化
mybatis 二级缓存需要将查询结果映射的 pojo 实现 java.io.serializable 接口,如果不实现则抛出异常:
org.apache.ibatis.cache.CacheException: Error serializing object. Cause: java.io.NotSerializableException: com.sihai.mybatis.po.User
二级缓存可以将内存的数据写到磁盘,存在对象的序列化和反序列化,所以要实现 java.io.serializable 接口。
如果结果映射的 pojo 中还包括了 pojo ,都要实现 java.io.serializable 接口。
4.4 二级缓存禁用
对于变化频率较高的 sql ,需要禁用二级缓存:
在statement中设置 useCache=false 可以禁用当前 select 语句的二级缓存,即每次查询都会发出 sql 去查询, 默认情况是 true ,即该 sql 使用二级缓存。
<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">
4.5 刷新缓存
如果 sqlsession 操作 commit 操作,对二级缓存进行刷新(全局清空)。
设置 statement 的 flushCache 是否刷新缓存,默认值是 true 。
4.6 测试代码
//二级缓存的测试 @Test public void testCache2() throws Exception { SqlSession sqlSession1 = sqlSessionFactory.openSession(); SqlSession sqlSession2 = sqlSessionFactory.openSession(); SqlSession sqlSession3 = sqlSessionFactory.openSession(); UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class); UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class); UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class); //第一次查询用户id为1的用户 User user = userMapper1.findUserById(1); System.out.println(user); sqlSession1.close(); //中间修改用户要清空缓存,目的防止查询出脏数据 /*user.setUsername("测试用户2"); userMapper3.updateUser(user); sqlSession3.commit(); sqlSession3.close();*/ //第二次查询用户id为1的用户 User user2 = userMapper2.findUserById(1); System.out.println(user2); sqlSession2.close(); }
4.7 mybatis 的 cache 参数
mybatis 的 cache 参数只适用于 mybatis 维护缓存。
flushInterval (刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。
size (引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值是 1024 。
readOnly (只读)属性可以被设置为 true 或 false 。只读的缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false 。
如下例子:
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
这个更高级的配置创建了一个 FIFO 缓存 , 并每隔 60 秒刷新 , 存数结果对象或列表的 512 个引用 , 而且返回的对象被认为是只读的 , 因此在不同线程中的调用者之间修改它们会导致冲突。可用的收回策略有 , 默认的是 LRU:
1. LRU – 最近最少使用的 : 移除最长时间不被使用的对象。
2. FIFO – 先进先出 : 按对象进入缓存的顺序来移除它们。
3. SOFT – 软引用 : 移除基于垃圾回收器状态和软引用规则的对象。
4. WEAK – 弱引用 : 更积极地移除基于垃圾收集器状态和弱引用规则的对象。
5 mybatis 和 ehcache 缓存框架整合
mybatis 二级缓存通过 ehcache 维护缓存数据。
5.1 分布缓存
将缓存数据数据进行分布式管理。
5.2 mybatis 和 ehcache 思路
通过 mybatis 和 ehcache 框架进行整合,就可以把缓存数据的管理托管给 ehcache 。
在 mybatis 中提供一个 cache 接口,只要实现 cache 接口就可以把缓存数据灵活的管理起来。
mybatis 中默认实现:
5.3 下载和 ehcache 整合的 jar 包
ehcache 对 cache 接口的实现类:
5.4 配置 ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"> <!--diskStore:缓存数据持久化的目录 地址 --> <diskStore path="F:\develop\ehcache" /> <defaultCache maxElementsInMemory="1000" maxElementsOnDisk="10000000" eternal="false" overflowToDisk="false" diskPersistent="true" timeToIdleSeconds="120" timeToLiveSeconds="120" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> </defaultCache> </ehcache>
5.5 整合测试
在 mapper.xml 添加 ehcache 配置:
<!-- 开启二级缓存 --> <!-- 单位:毫秒 --> <cache type="org.mybatis.caches.ehcache.EhcacheCache"> <property name="timeToIdleSeconds" value="12000"/> <property name="timeToLiveSeconds" value="3600"/> <!-- 同ehcache参数maxElementsInMemory --> <property name="maxEntriesLocalHeap" value="1000"/> <!-- 同ehcache参数maxElementsOnDisk --> <property name="maxEntriesLocalDisk" value="10000000"/> <property name="memoryStoreEvictionPolicy" value="LRU"/> </cache>
6 二级缓存的 应用场景
对查询频率高,变化频率低的数据建议使用二级缓存。
对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用 mybatis 二级缓存技术降低数据库访问量,提高访问速度,业务场景比如:耗时较高的统计分析 sql 、电话账单查询 sql 等。
实现方法如下:通过 设置刷新间隔时间,由 mybatis 每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔 f lushInterval ,比如设置为 30 分钟、 60 分钟、 24 小时等,根据需求而定。
7 mybatis 局限性
mybatis 二级缓存对 细粒度的数据级别 的缓存实现不好,比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用 mybatis 的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,因为 mybaits 的二级缓存区域以 mapper 为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空。解决此类问题需要在业务层根据需求对数据有针对性缓存。
以上所述就是小编给大家介绍的《mybatis教程--查询缓存(一级缓存二级缓存和整合ehcache)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- SpringBoot 实战 (十一) | 整合数据缓存 Cache
- Spring AOP整合redis 实现缓存统一管理
- Spring-boot-route(十二):整合 Redis 做为缓存
- SpringBoot整合MyBatis并使用Redis作为缓存组件的Demo
- SpringBoot整合MybatisPlus的简单教程(简单整合)
- springmvc教程--整合mybatis开发(spring+springMVC+mybatis整合开发)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。