【MyBatis框架】查询缓存-二级缓存-整合ehcache
mybatis整合ehcache
ehcache是一个分布式缓存框架。
1.分布缓存
我们系统为了提高系统并发,性能、一般对系统进行分布式部署(集群部署方式)
不使用分布缓存,缓存的数据在各各服务单独存储,不方便系统开发。所以要使用分布式缓存对缓存数据进行集中管理。
mybatis无法实现分布式缓存,需要和其它分布式缓存框架进行整合。
2.整合方法(掌握)
mybatis提供了一个cache接口,如果要实现自己的缓存逻辑,实现cache接口开发即可。
mybatis和ehcache整合,mybatis和ehcache整合包中提供了一个cache接口的实现类。
mybatis默认实现cache类(接口)是:
此接口在MyBatis-3.2.7.jar下的org.apache.ibatis.cache包下的Cache.class
MyBatis默认实现支持的cache类是:
可以根据它来写新的实现类
3.加入ehcache包
ehcache-core-2.6.5.jar和mybatis-ehcache-1.0.2.jar
一个是ehcache自己的,一个是和mybatis的整合包
4.整合ehcache
配置mapper中cache中的type为ehcache对cache接口的实现类型。
我们在mybatis-ehcache-1.0.2.jar下找到org.mybatis.caches.ehcache包下有EhcacheCache.class类,这个就是ehcache整合mybatis的Cache接口的实现
UserMapper.xml:
5.加入ehcache的配置文件
在classpath下配置ehcache.xml
测试:
结果和输出日志:
整合ehcache成功!
6.二级应用场景
对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度,业务场景比如:耗时较高的统计分析sql、电话账单查询sql等。
实现方法如下:通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定。
7.二级缓存局限性
mybatis二级缓存对细粒度的数据级别的缓存实现不好,比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用mybatis的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空。解决此类问题需要在业务层根据需求对数据有针对性缓存。
ehcache是一个分布式缓存框架。
1.分布缓存
我们系统为了提高系统并发,性能、一般对系统进行分布式部署(集群部署方式)
如图
不使用分布缓存,缓存的数据在各各服务单独存储,不方便系统开发。所以要使用分布式缓存对缓存数据进行集中管理。
mybatis无法实现分布式缓存,需要和其它分布式缓存框架进行整合。
2.整合方法(掌握)
mybatis提供了一个cache接口,如果要实现自己的缓存逻辑,实现cache接口开发即可。
mybatis和ehcache整合,mybatis和ehcache整合包中提供了一个cache接口的实现类。
mybatis默认实现cache类(接口)是:
此接口在MyBatis-3.2.7.jar下的org.apache.ibatis.cache包下的Cache.class
- package org.apache.ibatis.cache;
- import java.util.concurrent.locks.ReadWriteLock;
- public interface Cache {
- //缓存在唯一标示
- String getId();
- //存入到缓存中
- void putObject(Object key, Object value);
- //根据key取出缓存
- Object getObject(Object key);
- //移除key
- Object removeObject(Object key);
- void clear();
- int getSize();
- ReadWriteLock getReadWriteLock();
- }
MyBatis默认实现支持的cache类是:
- package org.apache.ibatis.cache.impl;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.concurrent.locks.ReadWriteLock;
- import org.apache.ibatis.cache.Cache;
- import org.apache.ibatis.cache.CacheException;
- public class PerpetualCache implements Cache {
- private String id;
- private Map<Object, Object> cache = new HashMap<Object, Object>();
- public PerpetualCache(String id)
- {
- this.id = id;
- }
- public String getId() {
- return id;
- }
- public int getSize() {
- return cache.size();
- }
- public void putObject(Object key, Object value) {
- cache.put(key, value);
- }
- public Object getObject(Object key) {
- return cache.get(key);
- }
- public Object removeObject(Object key) {
- return cache.remove(key);
- }
- public void clear() {
- cache.clear();
- }
- public ReadWriteLock getReadWriteLock() {
- return null;
- }
- public boolean equals(Object o) {
- if (getId() == null)
- throw new CacheException("Cache instances require an ID.");
- if (this == o) return true;
- if (!(o instanceof Cache)) return false;
- Cache otherCache = (Cache) o;
- return getId().equals(otherCache.getId());
- }
- public int hashCode() {
- if (getId() == null)
- throw new CacheException("Cache instances require an ID.");
- return getId().hashCode();
- }
- }
3.加入ehcache包
ehcache-core-2.6.5.jar和mybatis-ehcache-1.0.2.jar
一个是ehcache自己的,一个是和mybatis的整合包
4.整合ehcache
配置mapper中cache中的type为ehcache对cache接口的实现类型。
我们在mybatis-ehcache-1.0.2.jar下找到org.mybatis.caches.ehcache包下有EhcacheCache.class类,这个就是ehcache整合mybatis的Cache接口的实现
UserMapper.xml:
- <mapper namespace="cn.edu.hpu.mybatis.mapper.UserMapper">
- <!-- 开启本Mapper的namespace下的二级缓存
- type:执行cache接口实现类的类型,mybatis默认使用PerpatualCache,
- 要和ehcache整合,需要配置type为ehcache实现cache接口的类型-->
- <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
- ......
- </mapper>
5.加入ehcache的配置文件
在classpath下配置ehcache.xml
- <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
- <diskStore path="F:\develop\ehcache" />
- <defaultCache
- maxElementsInMemory="1000"
- maxElementsOnDisk="10000000"
- eternal="false"
- overflowToDisk="false"
- timeToIdleSeconds="120"
- timeToLiveSeconds="120"
- diskExpiryThreadIntervalSeconds="120"
- memoryStoreEvictionPolicy="LRU">
- </defaultCache>
- </ehcache>
测试:
- //测试二级缓存
- @Test
- public void testCache2() throws Exception{
- SqlSession sqlSession1 = sqlSessionFactory.openSession();
- SqlSession sqlSession2 = sqlSessionFactory.openSession();
- SqlSession sqlSession3 = sqlSessionFactory.openSession();
- UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);//创建代理对象
- //下边查询使用一个SqlSession
- //第一次发起请求,查询id为1的用户
- User user1 = userMapper1.findUserById(1);
- System.out.println(user1.getUsername());
- //不关闭SqlSession无法写进二级缓存区域中
- sqlSession1.close();
- UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);//创建代理对象
- //第二次发起请求,查询id为1的用户
- User user2 = userMapper2.findUserById(1);
- System.out.println(user2.getUsername());
- sqlSession2.close();
- }
- DEBUG [main] - Cache Hit Ratio [cn.edu.hpu.mybatis.mapper.UserMapper]: 0.0
- DEBUG [main] - Opening JDBC Connection
- DEBUG [main] - Created connection 4554017.
- DEBUG [main] - Setting autocommit to false on JDBC Connection [[email protected]]
- DEBUG [main] - ==> Preparing: SELECT * FROM USER WHERE id=?
- DEBUG [main] - ==> Parameters: 1(Integer)
- DEBUG [main] - <== Total: 1
- 张明明
- DEBUG [main] - Resetting autocommit to true on JDBC Connection [[email protected]]
- DEBUG [main] - Closing JDBC Connection [[email protected]]
- DEBUG [main] - Returned connection 4554017 to pool.
- DEBUG [main] - Cache Hit Ratio [cn.edu.hpu.mybatis.mapper.UserMapper]: 0.5
- 张明明
整合ehcache成功!
6.二级应用场景
对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度,业务场景比如:耗时较高的统计分析sql、电话账单查询sql等。
实现方法如下:通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定。
7.二级缓存局限性
mybatis二级缓存对细粒度的数据级别的缓存实现不好,比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用mybatis的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空。解决此类问题需要在业务层根据需求对数据有针对性缓存。