WEB性能优化--缓存

缓存是位于内存中的一块用于临时存储数据的区域,在java web的开发中,主要用来优化程序与数据库的交互,将频繁的sql查询操做或增,删,改(通常的,查询操做远大于增,删,改的操做),只当第一次请求时,直接请求数据库,而后把结果放到缓存中,后续若再有相同的操做请求,直接去缓存中取值,大大减轻了数据库服务器的压力.(java项目的开发中,数据库是最薄弱的一环)

一.缓存的简单模拟实现代码
1>没有缓存时的代码java

public User findById(Integer id){  

String sql="SELECT * FROM T_USER WHERE id=?";
return DBHelp.executeQueryForObject(User.class,sql,id);
}

2>加上缓存后的代码web

public User findById(Integer id){   

/**首先去缓存中查找对象,有就直接返回;  
没有在去数据库中操做,而且把操做后的结果放入缓存中,方便后续的使用 */  
User user = cache.get("user"+id);  
if(user==null){  
String sql="SELECT * FROM T_USER WHERE id=?";  
return DBHelp.executeQueryForObject(User.class,sql,id);  
cache.set("user"+id,user); 
}  
return user;  
}

3>cache的简单模拟实现算法

缓存的原理:缓存的内部实现是一个Map,Map<key,Object>中的key通常是具备标示性的给定,如user:0-->new User.
另外,缓存会基于指定的淘汰策略机制,决定数据的保留或移除.常见的缓存淘汰策略有三种:
1.基于数量
1.1 FIFO(first in first out):先进先出
弊端:若先出去的正好是常常要被请求的操做,这样会大大影响效率
1.2 LRU:最近最长被使用
1.3 JVM
1.4 ...
2.基于时间
3.基于数量+时间
具体说明以下:
当缓存须要被清理时(好比空间占用已经接近临界值了),须要使用某种淘汰算法来决定清理掉哪些数据。经常使用的淘汰算法有下面几种:
FIFO:First In First Out,先进先出。判断被存储的时间,离目前最远的数据优先被淘汰。
LRU:Least Recently Used,最近最少使用。判断最近被使用的时间,目前最远的数据优先被淘汰。
LFU:Least Frequently Used,最不常常使用。在一段时间内,数据被使用次数最少的,优先被淘汰。sql

public class SimpleCache{

//HashTable是线程安全的,且不容许有null的key
private static Map<String,Object> cache = new HashTable<>();

/**取值,从缓存里获取数据,叫命中缓存*/
public static Object getObject(String key){
//判断缓存中是否包含key,包含返回映射值;不包含返回null
if(map.containsKey(key)){
   return cache.get(key);
 }
 return null;
}

//放值
public static void setObject(String key,Object obj){
cache.put(key,obj);
}

//删除指定值并返回
publlic static Object removeObject(String key){
return cache.remove(key);
}

}

经常使用缓存的开源框架:EHCACHE
通常的缓存都是本地缓存.
分布式缓存 Redis , Memcached
问题:若查询的是单个结果集,能够直接去缓存中取值;但若是请求操做的结果集是一个集合,如List
则要进行缓存的时时刷新,以获取最新的结果.如论坛中,不少人在同一时间段内发帖,后台就必须不断的作insert/update/delete操做,操做完后,应该把原先放在缓存中的数据删除,这样,当用户刷新时,获取的是最新的数据,而不是缓存中没有更新的数据.
分布式缓存能够配置多台主机用于缓存,组成一个集群,这样当一台设备遇到故障后,能够将任务分摊到集群中的其余设备上,不影响正常运行.
---
EHCACHE的使用:
在MAVEN中配置EHCACHE的依赖:ehcache.xml(必需要叫这个名)
数据库

<ehcache>  
  <diskStore path="java.io.tmpdir" /> <!--java.io.tmpdir为系统常量,表示当前用户下的临时文件夹-->  
  <defaultCache
    maxElementInMemory="1000"
    eternal="false"
    timeToIdleSeconds="120"
    timeToLiveSeconds="120"
    overflowToDisk="true"
   />
  <cache name="users"
    maxElementInMemory="1000"
    eternal="false" <!--表示是否永久存储,若是为true,将致使下面两个参数无效-->
    timeToIdleSeconds="120"//闲置时间(最后访问时间-当前时间)
    timeToLiveSeconds="120"//存活时间(当前时间-建立时间,闲置时间<=存活时间)
    overflowToDisk="true"// 
<ehcache/>

EhCacheUtil.java缓存

import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;

public class EhCacheUtil{
  private static CacheManager cacheManager = new CacheManager();
  
public static void set(String key,Object value){
Ehcache ehcache = cacheManager.getEhcache("myCache");
Element element = new Element(key,value);
ehcace.put(element);
} 

public static Object get(String key){
Ehcache ehcache = cacheManager.getEhcache("myCache");
Element element = ehcache.get(key);
if(element!=null){
  return element.getObjectValue();
}
return null;
}

public static void remove(String key){
Ehcache ehcache = cacheManager.getEhcache("myCache");
ehcache.remove(key);
}
}

测试代码:安全

public class TestDao{
private Logger logger = LoggerFactory.getLogger(TestDao.class);  

//查询单个结果
public Message findById(Integer id){  

Message message = (Message)EhCacheUtil.get("Message:"+id);
if(message == null){
String sql = "select * from t_message where id=?";
message = DBHelp.query(sql,new BeanHandler<>(Message.class,id));
EhCacheUtil.set("Message:"+id,message);
}else{
logger.debug("load message from cache");
}
return message;
}

//查询多个结果(须要手动的刷新缓存) 
public List<Message> findAll(){

List<Message> messageList = EHCacheUtil.get("messageList");
if(messageList == null){
String sql = "select * from t_message order by id desc";
messageList = DBHelp.query(sql,new BeanListHandler<>(Message.class));
EhCacheUtil.set("messageList",messageList);
}
return messageList;
}

//新增数据
public void save(Message message){
String sql = "insert into t_message(message,author) values(?,?)";
DBHelp.update(sql,message.getMessage,message.getAuthor);
//删除缓存中已有的集合
EhCacheUtil.remove("messageList");
}

public static  void main(String[] args){
TestDao testDao = new TestDao();
List<Message> messgeList = testDao.findAll();//from DB
//messageList =  testDao.findAll();from cache

//中间作了insert操做
Message message = new Message("你妹","王宏");
testDao.save(message);//insert removeCache
messageList =  testDao.findAll();from DB
messageList =  testDao.findAll();from cache
//使用断言
Assert.assertEquals(25,messageList.size());
} 
}
相关文章
相关标签/搜索