缓存是位于内存中的一块用于临时存储数据的区域,在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());
}
}
来源:https://www.cnblogs.com/Go-WH/p/6592242.html