WEB性能优化--缓存

时光总嘲笑我的痴心妄想 提交于 2020-01-04 03:38:31

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

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

public User findById(Integer id){  

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

2>加上缓存后的代码

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,最不经常使用。在一段时间内,数据被使用次数最少的,优先被淘汰。

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());
} 
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!