缓存是位于内存中的一块用于临时存储数据的区域,在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