一.緩存的簡單模擬實現代碼
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()); } }