1、为什么需要缓存
拉高程序的性能
2、什么样的数据需要缓存
很少被修改或根本不改的数据
3、业务场景比如:耗时较高的统计分析sql、电话账单查询sql等
4、ehcache是什么?
Ehcache 是现在最流行的纯Java开源缓存框架,配置简单、结构清晰、功能强大
注1:本章介绍的是2.X版本,3.x的版本和2.x的版本API差异比较大
5、ehcache的特点
1 、够快 Ehcache的发行有一段时长了,经过几年的努力和不计其数的性能测试,Ehcache终被设计于large, high
concurrency systems.
2 、够简单 开发者提供的接口非常简单明了,从Ehcache的搭建到运用运行仅仅需要的是你宝贵的几分钟。其实很多开发者都不知道自己用在用Ehcache,Ehcache被广泛的运用于其他的开源项目
3 、够袖珍 关于这点的特性,官方给了一个很可爱的名字small foot print ,一般Ehcache的发布版本不会到2M,V 2.2.3 才 668KB。
4 、够轻量 核心程序仅仅依赖slf4j这一个包,没有之一!
5、 好扩展 Ehcache提供了对大数据的内存和硬盘的存储,最近版本允许多实例、保存对象高灵活性、提供LRU、LFU、FIFO淘汰算法,基础属性支持热配置、支持的插件多
6 、监听器 缓存管理器监听器 (CacheManagerListener)和 缓存监听器(CacheEvenListener),做一些统计或数据一致性广播挺好用的
7、 分布式缓存 从Ehcache 1.2开始,支持高性能的分布式缓存,兼具灵活性和扩展性
核心接口:
CacheManager:缓存管理器
Cache:缓存对象,缓存管理器内可以放置若干cache,存放数据的实质,所有cache都实现了Ehcache接口
Element:单条缓存数据的组成单位
导入相关依赖
org.springframework
spring-context-support
${spring.version}
org.mybatis.caches
mybatis-ehcache
1.1.0
net.sf.ehcache
ehcache
2.10.0
修改日志配置,因为ehcache使用了Slf4j作为日志输出
日志我们使用slf4j,并用log4j来实现。SLF4J不同于其他日志类库,与其它有很大的不同。
SLF4J(Simple logging Facade for Java)不是一个真正的日志实现,而是一个抽象层( abstraction layer),
它允许你在后台使用任意一个日志类库
2.9.1
3.2.0
1.7.13
org.slf4j
slf4j-api
${slf4j.version}
org.slf4j
jcl-over-slf4j
${slf4j.version}
runtime
org.apache.logging.log4j
log4j-api
${log4j2.version}
org.apache.logging.log4j
log4j-core
${log4j2.version}
org.apache.logging.log4j
log4j-slf4j-impl
${log4j2.version}
org.apache.logging.log4j
log4j-web
${log4j2.version}
runtime
com.lmax
disruptor
${log4j2.disruptor.version}
在Resource中添加一个ehcache.xml的配置文件
开启mybatis的二级缓存,applicationContext-mybatis.xml中添加
!--设置mybaits对缓存的支持-->
true
false
true
在bookMapper.xml中配置cache
可以通过select标签的useCache属性打开或关闭二级缓存
测试
@Test
public void cacheMany() {
Map map = new HashMap();
map.put("bname", StringUtils.toLikeStr("圣墟"));
pageBean.setPage(3);
List
redis常用类
实现 mybatis 的二级缓存,一般来说有如下两种方式:
添加redis相关依赖
2.9.0
1.7.1.RELEASE
redis.clients
jedis
${redis.version}
org.springframework.data
spring-data-redis
${redis.spring.version}
** jackson**
2.9.3
com.fasterxml.jackson.core
jackson-databind
${jackson.version}
com.fasterxml.jackson.core
jackson-core
${jackson.version}
com.fasterxml.jackson.core
jackson-annotations
${jackson.version}
添加两个redis的配置文件,并将redis.properties和applicationContext-redis.xml配置到applicationContext.xml文件中
redis.properties
redis.hostName=192.168.19.128
redis.port=6379
redis.password=123456
redis.timeout=10000
redis.maxIdle=300
redis.maxTotal=1000
redis.maxWaitMillis=1000
redis.minEvictableIdleTimeMillis=300000
redis.numTestsPerEvictionRun=1024
redis.timeBetweenEvictionRunsMillis=30000
redis.testOnBorrow=true
redis.testWhileIdle=true
applicationContext-redis.xml
applicationContext-redis.xml
将redis缓存引入到mybatis中
1、RedisCache,实现org.apache.ibatis.cache.Cache接口
package com.Tang.util;
import org.apache.ibatis.cache.Cache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class RedisCache implements Cache //实现类
{
private static final Logger logger = LoggerFactory.getLogger(RedisCache.class);
private static RedisTemplate redisTemplate;
private final String id;
/**
* The {@code ReadWriteLock}.
*/
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
@Override
public ReadWriteLock getReadWriteLock()
{
return this.readWriteLock;
}
public static void setRedisTemplate(RedisTemplate redisTemplate) {
RedisCache.redisTemplate = redisTemplate;
}
public RedisCache(final String id) {
if (id == null) {
throw new IllegalArgumentException("Cache instances require an ID");
}
logger.debug("MybatisRedisCache:id=" + id);
this.id = id;
}
@Override
public String getId() {
return this.id;
}
@Override
public void putObject(Object key, Object value) {
try{
logger.info(">>>>>>>>>>>>>>>>>>>>>>>>putObject: key="+key+",value="+value);
if(null!=value)
redisTemplate.opsForValue().set(key.toString(),value,60, TimeUnit.SECONDS);
}catch (Exception e){
e.printStackTrace();
logger.error("redis保存数据异常!");
}
}
@Override
public Object getObject(Object key) {
try{
logger.info(">>>>>>>>>>>>>>>>>>>>>>>>getObject: key="+key);
if(null!=key)
return redisTemplate.opsForValue().get(key.toString());
}catch (Exception e){
e.printStackTrace();
logger.error("redis获取数据异常!");
}
return null;
}
@Override
public Object removeObject(Object key) {
try{
if(null!=key)
return redisTemplate.expire(key.toString(),1,TimeUnit.DAYS);
}catch (Exception e){
e.printStackTrace();
logger.error("redis获取数据异常!");
}
return null;
}
@Override
public void clear() {
Long size=redisTemplate.execute(new RedisCallback() {
@Override
public Long doInRedis(RedisConnection redisConnection) throws DataAccessException {
Long size = redisConnection.dbSize();
//连接清除数据
redisConnection.flushDb();
redisConnection.flushAll();
return size;
}
});
logger.info(">>>>>>>>>>>>>>>>>>>>>>>>clear: 清除了" + size + "个对象");
}
@Override
public int getSize() {
Long size = redisTemplate.execute(new RedisCallback() {
@Override
public Long doInRedis(RedisConnection connection)
throws DataAccessException {
return connection.dbSize();
}
});
return size.intValue();
}
}
2、中间类“RedisCacheTransfer”,解决RedisCache中RedisTemplate的静态注入
package com.Tang.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
public class RedisCacheTransfer {
@Autowired
public void setRedisTemplate(RedisTemplate redisTemplate) {
RedisCache.setRedisTemplate(redisTemplate);
}
}
spring与mybatis整合文件中开发二级缓存
true
false
true
在BookMapper.xml中添加自定义cache功能
测试
@Test
public void cacheMany() {
Map map = new HashMap();
map.put("bname", StringUtils.toLikeStr("圣墟"));
pageBean.setPage(3);
List aaaa = this.bookService.listPager(map, pageBean);
for (Map m : aaaa) {
System.out.println(m);
}
List aaaa2 = this.bookService.listPager(map, pageBean);
for (Map m : aaaa2) {
System.out.println(m);
}
}
@Test
public void cacheSimgle() {
Book b1 = this.bookService.selectByPrimaryKey(29);
System.out.println(b1);
Book b2 = this.bookService.selectByPrimaryKey(29);
System.out.println(b2);
}