緩存失效策略
MySQL緩存機制簡單的說就是緩存sql文本及查詢結果,如果運行相同的sql,伺服器直接從緩存中取到結果,而不需要再去解析和執行sql。如果表更改 了,那麼使用這個表的所有緩沖查詢將不再有效,查詢緩存值的相關條目被清空。更改指的是表中任何數據或是結構的改變,包括INSERT、UPDATE、 DELETE、TRUNCATE、ALTER TABLE、DROP TABLE或DROP DATABASE等,也包括那些映射到改變了的表的使用MERGE表的查詢。顯然,這對於頻繁更新的表,查詢緩存是不適合的,而對於一些不常改變數據且有 大量相同sql查詢的表,查詢緩存會節約很大的性能。
命中條件
緩存存在一個hash表中,通過查詢SQL,查詢資料庫,客戶端協議等作為key.在判斷是否命中前,MySQL不會解析SQL,而是直接使用SQL去查詢緩存,SQL任何字元上的不同,如空格,注釋,都會導致緩存不命中.
如果查詢中有不確定數據,例如CURRENT_DATE()和NOW()函數,那麼查詢完畢後則不會被緩存.所以,包含不確定數據的查詢是肯定不會找到可用緩存的
工作流程
1. 伺服器接收SQL,以SQL和一些其他條件為key查找緩存表(額外性能消耗)
2. 如果找到了緩存,則直接返回緩存(性能提升)
3. 如果沒有找到緩存,則執行SQL查詢,包括原來的SQL解析,優化等.
4. 執行完SQL查詢結果以後,將SQL查詢結果存入緩存表(額外性能消耗)
緩存失效
當某個表正在寫入數據,則這個表的緩存(命中檢查,緩存寫入等)將會處於失效狀態.在Innodb中,如果某個事務修改了表,則這個表的緩存在事務提交前都會處於失效狀態,在這個事務提交前,這個表的相關查詢都無法被緩存.
緩存的內存管理
緩存會在內存中開辟一塊內存(query_cache_size)來維護緩存數據,其中有大概40K的空間是用來維護緩存的元數據的,例如空間內存,數據表和查詢結果的映射,SQL和查詢結果的映射等.
MySQL將這個大內存塊分為小的內存塊(query_cache_min_res_unit),每個小塊中存儲自身的類型,大小和查詢結果數據,還有指向前後內存塊的指針.
MySQL需要設置單個小存儲塊的大小,在SQL查詢開始(還未得到結果)時就去申請一塊空間,所以即使你的緩存數據沒有達到這個大小,也需要用這個大小的數據塊去存(這點跟Linux文件系統的Block一樣).如果結果超出這個內存塊的大小,則需要再去申請一個內存塊.當查詢完成發現申請的內存塊有富餘,則會將富餘的空間釋放掉,這就會造成內存碎片問題,見下圖
此處查詢1和查詢2之間的空白部分就是內存碎片,這部分空閑內存是有查詢1查詢完以後釋放的,假設這個空間大小小於MySQL設定的內存塊大小,則無法再被使用,造成碎片問題
在查詢開始時申請分配內存Block需要鎖住整個空閑內存區,所以分配內存塊是非常消耗資源的.注意這里所說的分配內存是在MySQL初始化時就開辟的那塊內存上分配的.
緩存的使用時機
衡量打開緩存是否對系統有性能提升是一個很難的話題
1. 通過緩存命中率判斷, 緩存命中率 = 緩存命中次數 (Qcache_hits) / 查詢次數 (Com_select)
2. 通過緩存寫入率, 寫入率 = 緩存寫入次數 (Qcache_inserts) / 查詢次數 (Qcache_inserts)
3. 通過 命中-寫入率 判斷, 比率 = 命中次數 (Qcache_hits) / 寫入次數 (Qcache_inserts), 高性能MySQL中稱之為比較能反映性能提升的指數,一般來說達到3:1則算是查詢緩存有效,而最好能夠達到10:1
緩存配置參數
1. query_cache_type: 是否打開緩存
可選項
1) OFF: 關閉
2) ON: 總是打開
3) DEMAND: 只有明確寫了SQL_CACHE的查詢才會吸入緩存
2. query_cache_size: 緩存使用的總內存空間大小,單位是位元組,這個值必須是1024的整數倍,否則MySQL實際分配可能跟這個數值不同(感覺這個應該跟文件系統的blcok大小有關)
3. query_cache_min_res_unit: 分配內存塊時的最小單位大小
4. query_cache_limit: MySQL能夠緩存的最大結果,如果超出,則增加 Qcache_not_cached的值,並刪除查詢結果
5. query_cache_wlock_invalidate: 如果某個數據表被鎖住,是否仍然從緩存中返回數據,默認是OFF,表示仍然可以返回
GLOBAL STAUS 中 關於 緩存的參數解釋:
Qcache_free_blocks: 緩存池中空閑塊的個數
Qcache_free_memory: 緩存中空閑內存量
Qcache_hits: 緩存命中次數
Qcache_inserts: 緩存寫入次數
Qcache_lowmen_prunes: 因內存不足刪除緩存次數
Qcache_not_cached: 查詢未被緩存次數,例如查詢結果超出緩存塊大小,查詢中包含可變函數等
Qcache_queries_in_cache: 當前緩存中緩存的SQL數量
Qcache_total_blocks: 緩存總block數
減少碎片策略
1. 選擇合適的block大小
2. 使用 FLUSH QUERY CACHE 命令整理碎片.這個命令在整理緩存期間,會導致其他連接無法使用查詢緩存
PS: 清空緩存的命令式 RESET QUERY CACHE
❷ 會員緩存失敗
出現緩存失敗的情況有以下幾種可能:
1、網路斷開,導致緩存失敗,請檢查網路是否正常。
2、視頻本身有問題,導致緩存失敗。
3、有些視頻因為版權原因,本身就是無法緩存的。
緩存文件寫入失敗解決方法
「滑鼠雙擊此電腦,右鍵單擊本地磁碟,選擇屬性,彈出窗口,切換到工具選項欄,點擊檢查,選擇掃描驅動器,待掃描完成即可,若還是不能解決的話,在屬性窗口,切換到硬體選項欄,選中磁碟驅動器,點擊屬性,切換到卷選項欄,選擇寫入,再切換到策略選項欄,取消啟用設備上的寫入緩存前面的勾,點擊確定即可。」
緩存文件寫入失敗會在計算機系統中出現的問題
CPU高速緩存是用於減少處理器訪問內存所需平均時間的部件。在金字塔式存儲體系中它位於自頂向下的第二層,僅次於CPU寄存器。其容量遠小於內存,但速度卻可以接近處理器的頻率。
當處理器發出內存訪問請求時,會先查看緩存內是否有請求數據。如果存在(命中),則不經訪問內存直接返回該數據;如果不存在(失效),則要先把內存中的相應數據載入緩存,再將其返回處理器。緩存之所以有效,主要是因為程序運行時對內存的訪問呈現局部性特徵。這種局部性既包括空間局部性,也包括時間局部性。有效利用這種局部性,緩存可以達到極高的命中率。
緩存寫入失敗是什麼原因引起的?
一、非正常電腦關引起的:
如果是非正常關電腦引起的寫入緩存失敗,那就在【運行】中輸入【CHKDSK 盤符】。
系統錯誤:
1、打開我的電腦,打開本地磁碟屬性,在彈出的對話框中選擇【工具】--【開始檢查】,
2、在檢查磁碟對話框中。把下面的兩項打上勾,檢查一下。就可以了,如果不能解決就往下面看。
3、打開【本地磁碟】屬性對話框,找到【硬體】
4、打開【策略】對話框,把【啟用磁碟上的寫入緩存】前面的勾去了。
二、硬碟出現壞道引起的:
1、這種情況如果硬碟壞道多了,最好的辦法是直接換硬碟。如果壞道不是很多,電腦上也沒有什麼重要數據,那就可以先用工具處理一下接著用。但這樣的方法保證不了硬碟能用多長時間。
2、先進入MHDD測試一下硬碟情況。
3、測試出了硬碟出現問題的地方,然後進入PE啟用【分區工具DISKGENIUS】。
4、通過剛才測試出來的結果,算出壞道出現的容量。用分區工具把有壞道的部分,單獨分出來不用。把好的分出來接著用,但是這樣出來重要的數據就不要放在這個硬碟上了。
❸ ehcache java 對象緩存怎麼實現
1.技術背景:
系統緩存是位於應用程序與物理數據源之間,用於臨時存放復制數據的內存區域,目的是為減少應用程序對物理數據源訪問的次數,從而提高應用程序的運行性能。緩存設想內存是有限的,緩存的時效性也是有限的,所以可以設定內存數量的大小可以執行失效演算法,可以在內存滿了的情況下,按照最少訪問等演算法將緩存直接移除或切換到硬碟上。
Ehcache從Hibernate發展而來,逐漸涵蓋了Cache界的全部功能,是目前發展勢頭最好的一個項目,具有快速、簡單、低消耗、擴展性強、支持對象或序列化緩存,支持緩存或元素的失效,提供LRU、LFU和FIFO緩存策略,支持內存緩存和硬碟緩存和分布式緩存機制等特點。其中Cache的存儲方式為內存或磁碟(ps:無須擔心容量問題)
2.EhCahe的類層次介紹:
主要分為三層,最上層是CacheManager,它是操作Ehcache的入口。可以通過CacheManager.getInstance()獲得一個單子的CacheManager,或者通過CacheManager的構造函數創建一個新的CacheManager。每個CacheManger都管理多個Cache。每個Cache都以一種類Hash的方式,關聯多個Element。Element就是我們用於存放緩存內容的地方。
3.環境搭建:
很簡單只需要將ehcache-2.1.0-distribution.tar.gz和ehcache-web-2.0.2-distribution.tar.gz擠壓的jar包放入WEB-INF/lib下。
再創建一個重要的配置文件ehcache.xml,可以從ehcache組件包中拷貝一個,也可以自己建立一個,需要放到classpath下,一般放於/WEB-INF/classed/ehcache.xml;具體的配置文件可以網上搜一下
4.實際運用
一個網站的首頁估計是被訪問次數最多的,我們可以考慮給首頁做一個頁面緩存;
緩存策略:應該是某個固定時間之內不變的,比如說2分鍾更新一次,以應用結構page-filter-action-service--db為例。
位置:頁面緩存做到盡量靠近客戶的地方,就是在page和filter之間,這樣的優點就是第一個用戶請求後,頁面被緩存,第二個用戶在請求,走到filter這個請求就結束了,需要在走到action-service--db,好處當然是伺服器壓力大大降低和客戶端頁面響應速度加快。
首頁頁面緩存存活時間定為2分鍾,也就是參數timeToLiveSeconds(緩存的存活時間)應該設置為120,同時timeToIdleSeconds(多長時間不訪問緩存,就清楚該緩存)最好也設為2分鍾或者小於2分鍾。
接著我們來看一下SimplePageCachingFilter的配置,
<filter>
<filter-name>indexCacheFilterfilter-name>
<filter-class>
net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter
<filter-class>
<filter>
<filter-mapping>
<filter-name>indexCacheFilterfilter-name>
<url-pattern>*index.actionurl-pattern>
<filter-mapping>
將上述代碼加入到web.xml,那麼當打開首頁時,你會發現2分鍾才會有一堆sql語句出現在控制台,也可以調整為5分鍾,總之一切盡在掌控之中。
當然,如果你像緩存首頁的部分內容時,你需要使用這個filter,我看一下:
<filter>
<filter-name>indexCacheFilterfilter-name>
<filter-class>
net.sf.ehcache.constructs.web.filter.
<filter-class>
filter>
<filter-mapping>
<filter-name>indexCacheFilterfilter-name>
<url-pattern>*/index_right.jsp<url-pattern>
<filter-mapping>
如此我們將jsp頁面通過jsp:include到其他頁面,這樣就做到了頁面局部緩存的效果,這一點貌似沒有oscache的tag好用。
此外cachefilter中還有一個特性,就是gzip,也就是緩存中的元素是被壓縮過的,如果客戶端瀏覽器支持壓縮的話,filter會直接返回壓縮過的流,這樣節省了帶寬,把解壓的工作交給了客戶端瀏覽即可,當然如果客戶端不支持gzip,那麼filter會把緩存的元素拿出來解壓後在返回給客戶端瀏覽器(大多數爬蟲是不支持gzip的,所以filter也會解壓後在返迴流)。
總之,Ehcache是一個非常輕量級的緩存實現,而且從1.2之後支持了集群,而且是hibernate默認的緩存provider,本文主要介紹Ehcahe對頁面緩存的支持,但是它的功能遠不止如此,要用好緩存,對J2ee中緩存的原理、適用范圍、適用場景等等都需要比較深刻的理解,這樣才能用好用對緩存。
為了大家通過實際例子加深了解與場景運用,在奉獻一個實例:
*在Spring中運用EhCache
適用任意一個現有開源CacheFramework,要求可以Cache系統中service或者DAO層的get/find等方法返回結果,如果數據更新(適用了Create/update/delete),則刷新cache中相應的內容。
根據需求,計劃適用SpringAOP+enCache來實現這個功能,採用ehCache原因之一就是Spring提供了enCache的支持,至於為何僅僅支持ehcache而不支持oscache和jbosscache就無從得知了。
AOP少不了攔截器,先創建一個實現了MethodInterceptor介面的攔截器,用來攔截Service/DAO的方法調用,攔截到方法後,搜索該方法的結果在cache中是否存在,如果存在,返回cache中結果,如果不存在返回資料庫查詢結果,並將結果返回到緩存。
,InitializingBean
{
privatestaticfinalLoglogger=LogFactory.getLog(MethodCacheInterceptor.class);
privateCachecache;
publicvoidsetCache(Cachecache){
this.cache=cache;
}
publicMethodCacheInterceptor(){
super();
}
/**
*攔截Service/DAO的方法,並查找該結果是否存在,如果存在就返回cache中的值,
*否則,返回資料庫查詢結果,並將查詢結果放入cache
*/
publicObjectinvoke(MethodInvocationinvocation)throwsThrowable{
StringtargetName=invocation.getThis().getClass().getName();
StringmethodName=invocation.getMethod().getName();
Object[]arguments=invocation.getArguments();
Objectresult;
logger.debug("Findobjectfromcacheis"+cache.getName());
StringcacheKey=getCacheKey(targetName,methodName,arguments);
Elementelement=cache.get(cacheKey);
Page13of26
if(element==null){
logger.debug("Holpmethod,Getmethodresultandcreatecache........!");
result=invocation.proceed();
element=newElement(cacheKey,(Serializable)result);
cache.put(element);
}
returnelement.getValue();
}
/**
*獲得cachekey的方法,cachekey是Cache中一個Element的唯一標識
*cachekey包括包名+類名+方法名,如com.co.cache.service.UserServiceImpl.getAllUser
*/
privateStringgetCacheKey(StringtargetName,StringmethodName,Object[]arguments){
StringBuffersb=newStringBuffer();
sb.append(targetName).append(".").append(methodName);
if((arguments!=null)&&(arguments.length!=0)){
for(inti=0;i<arguments.length;i++){
sb.append(".").append(arguments[i]);
}
}
returnsb.toString();
}
/**
*implementInitializingBean,檢查cache是否為空
*/
publicvoidafterPropertiesSet()throwsException{
Assert.notNull(cache,"Needacache.PleaseusesetCache(Cache)createit.");
}
}
上面的代碼可以看到,在方法invoke中,完成了搜索cache/新建cache的功能
隨後,再建立一個攔截器MethodCacheAfterAdvice,作用是在用戶進行create/update/delete操作時來刷新、remove相關cache內容,這個攔截器需要實現AfterRetruningAdvice介面,將會在所攔截的方法執行後執行在afterReturning(objectarg0,Methodarg1,Object[]arg2,objectarg3)方法中所預定的操作
,InitializingBean
{
privatestaticfinalLoglogger=LogFactory.getLog(MethodCacheAfterAdvice.class);
privateCachecache;
Page15of26
publicvoidsetCache(Cachecache){
this.cache=cache;
}
publicMethodCacheAfterAdvice(){
super();
}
publicvoidafterReturning(Objectarg0,Methodarg1,Object[]arg2,Objectarg3)throws
Throwable{
StringclassName=arg3.getClass().getName();
Listlist=cache.getKeys();
for(inti=0;i<list.size();i++){
StringcacheKey=String.valueOf(list.get(i));
if(cacheKey.startsWith(className)){
cache.remove(cacheKey);
logger.debug("removecache"+cacheKey);
}
}
}
publicvoidafterPropertiesSet()throwsException{
Assert.notNull(cache,"Needacache.PleaseusesetCache(Cache)createit.");
}
}
該方法獲取目標class的全名,如:com.co.cache.test.TestServiceImpl,然後循環cache的keylist,刷新/removecache中所有和該class相關的element。
接著就是配置encache的屬性,如最大緩存數量、cache刷新的時間等等。
<ehcache>
<diskStorepath="c:\myapp\cache"/>
<defaultCache
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
<cachename="DEFAULT_CACHE"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="300000"
timeToLiveSeconds="600000"
overflowToDisk="true"
/>
</ehcache>
這里需要注意的是defaultCache定義了一個默認的cache,這個Cache不能刪除,否則會拋出Nodefaultcacheisconfigured異常。另外由於使用攔截器來刷新Cache內容,因此在定義cache生命周期時可以定義較大的數值,timeToIdleSeconds="30000000",timeToLiveSeconds="6000000",好像還不夠大?
然後再將Cache和兩個攔截器配置到Spring的配置文件cache.xml中即可,需要創建兩個「切入點」,分別用於攔截不同方法名的方法。在配置application.xml並且導入cache.xml。這樣一個簡單的Spring+Encache框架就搭建完成。
❹ win10 啟用設備上的寫入緩存 關機就失效 怎麼辦
操作步驟:
1、按下Win+X組合鍵,喚出隱藏菜單,點擊裡面的「設備管理器」;
2、在Win10設備管理器窗口,點開磁碟驅動器項目,然後對著電腦硬碟單擊滑鼠右鍵,點擊選擇菜單中的「屬性」
3、在硬碟屬性對話框,點擊選擇「策略」選項卡,將「啟用此設備上的寫入緩存」更具個人需要設置成勾選,或取消勾選後,點擊底部「確定」即可
註:勾選「啟用此設備上的寫入緩存」是啟用該功能,取消勾選是關閉。
❺ 常見的緩存策略有哪些,如何做到緩存與 db 里的數據一致性
您: 種writer-reader架構般思路緩存更新階段由writer解決致性問題資料庫數據變化同步更新redis並確保緩存更新功 作完整性判斷檢查全部屬性數據使用自增版本號(或間戳)判斷否新 作置檢測優化降低掃描代價針近間周期內(依0min)資料庫更新數據集合應該比較redis進行檢查代價比較
❻ 該怎麼解決 Redis 緩存穿透和緩存雪崩問題
緩存雪崩: 由於緩存層承載著大量請求,有效地 保護了存儲層,但是如果緩存層由於某些原因不能提供服務,比如 Redis 節點掛掉了,熱點 key 全部失效了,在這些情況下,所有的請求都會直接請求到資料庫,可能會造成資料庫宕機的情況。
預防和解決緩存雪崩問題,可以從以下三個方面進行著手:
1、使用 Redis 高可用架構:使用 Redis 集群來保證 Redis 服務不會掛掉
2、緩存時間不一致: 給緩存的失效時間,加上一個隨機值,避免集體失效
3、限流降級策略:有一定的備案,比如個性推薦服務不可用了,換成熱點數據推薦服務
緩存穿透: 緩存穿透是指查詢一個根本不存在的數據,這樣的數據肯定不在緩存中,這會導致請求全部落到資料庫上,有可能出現資料庫宕機的情況。
預防和解決緩存穿透問題,可以考慮以下兩種方法:
1、緩存空對象: 將空值緩存起來,但是這樣就有一個問題,大量無效的空值將佔用空間,非常浪費。
2、布隆過濾器攔截: 將所有可能的查詢key 先映射到布隆過濾器中,查詢時先判斷key是否存在布隆過濾器中,存在才繼續向下執行,如果不存在,則直接返回。布隆過濾器有一定的誤判,所以需要你的業務允許一定的容錯性。
❼ 存,緩存命中如何,另外它本身沒有什麼緩存策略,而是依賴所用的網路庫的緩存策
很多人對二級緩存都不太了解,或者是有錯誤的認識,我一直想寫一篇文章介紹一下hibernate的二級緩存的,今天終於忍不住了。我的經驗主要來自hibernate2.1版本,基本原理和3.0、3.1是一樣的,請原諒我的頑固不化。hibernate的session提供了一級緩存,每個session,對同一個id進行兩次load,不會發送兩條sql給資料庫,但是session關閉的時候,一級緩存就失效了。二級緩存是SessionFactory級別的全局緩存,它底下可以使用不同的緩存類庫,比如ehcache、oscache等,需要設置hibernate.cache.provider_class,我們這里用ehcache,在2.1中就是hibernate.cache.provider_class=net.sf.hibernate.cache.EhCacheProvider如果使用查詢緩存,加上hibernate.cache.use_query_cache=true緩存可以簡單的看成一個Map,通過key在緩存裡面找value。Class的緩存對於一條記錄,也就是一個PO來說,是根據ID來找的,緩存的key就是ID,value是POJO。無論list,load還是iterate,只要讀出一個對象,都會填充緩存。但是list不會使用緩存,而iterate會先取資料庫selectid出來,然後一個id一個id的load,如果在緩存裡面有,就從緩存取,沒有的話就去資料庫load。假設是讀寫緩存,需要設置:如果你使用的二級緩存實現是ehcache的話,需要配置ehcache.xml其中eternal表示緩存是不是永遠不超時,timeToLiveSeconds是緩存中每個元素(這里也就是一個POJO)的超時時間,如果eternal="false",超過指定的時間,這個元素就被移走了。timeToIdleSeconds是發呆時間,是可選的。當往緩存裡面put的元素超過500個時,如果overflowToDisk="true",就會把緩存中的部分數據保存在硬碟上的臨時文件裡面。每個需要緩存的class都要這樣配置。如果你沒有配置,hibernate會在啟動的時候警告你,然後使用defaultCache的配置,這樣多個class會共享一個配置。當某個ID通過hibernate修改時,hibernate會知道,於是移除緩存。這樣大家可能會想,同樣的查詢條件,第一次先list,第二次再iterate,就可以使用到緩存了。實際上這是很難的,因為你無法判斷什麼時候是第一次,而且每次查詢的條件通常是不一樣的,假如資料庫裡面有100條記錄,id從1到100,第一次list的時候出了前50個id,第二次iterate的時候卻查詢到30至70號id,那麼30-50是從緩存裡面取的,51到70是從資料庫取的,共發送1+20條sql。所以我一直認為iterate沒有什麼用,總是會有1+N的問題。(題外話:有說法說大型查詢用list會把整個結果集裝入內存,很慢,而iterate只selectid比較好,但是大型查詢總是要分頁查的,誰也不會真的把整個結果集裝進來,假如一頁20條的話,iterate共需要執行21條語句,list雖然選擇若干欄位,比iterate第一條selectid語句慢一些,但只有一條語句,不裝入整個結果集hibernate還會根據資料庫方言做優化,比如使用mysql的limit,整體看來應該還是list快。)如果想要對list或者iterate查詢的結果緩存,就要用到查詢緩存了查詢緩存首先需要配置hibernate.cache.use_query_cache=true如果用ehcache,配置ehcache.xml,注意hibernate3.0以後不是net.sf的包名瞭然後query.setCacheable(true);//激活查詢緩存query.setCacheRegion("myCacheRegion");//指定要使用的cacheRegion,可選第二行指定要使用的cacheRegion是myCacheRegion,即你可以給每個查詢緩存做一個單獨的配置,使用setCacheRegion來做這個指定,需要在ehcache.xml裡面配置它:如果省略第二行,不設置cacheRegion的話,那麼會使用上面提到的標准查詢緩存的配置,也就是net.sf.hibernate.cache.StandardQueryCache對於查詢緩存來說,緩存的key是根據hql生成的sql,再加上參數,分頁等信息(可以通過日誌輸出看到,不過它的輸出不是很可讀,最好改一下它的代碼)。比如hql:fromCatcwherec.namelike?生成大致如下的sql:select*fromcatcwherec.namelike?參數是"tiger%",那麼查詢緩存的key*大約*是這樣的字元串(我是憑記憶寫的,並不精確,不過看了也該明白了):select*fromcatcwherec.namelike?,parameter:tiger%這樣,保證了同樣的查詢、同樣的參數等條件下具有一樣的key。現在說說緩存的value,如果是list方式的話,value在這里並不是整個結果集,而是查詢出來的這一串ID。也就是說,不管是list方法還是iterate方法,第一次查詢的時候,它們的查詢方式很它們平時的方式是一樣的,list執行一條sql,iterate執行1+N條,多出來的行為是它們填充了緩存。但是到同樣條件第二次查詢的時候,就都和iterate的行為一樣了,根據緩存的key去緩存裡面查到了value,value是一串id,然後在到class的緩存裡面去一個一個的load出來。這樣做是為了節約內存。可以看出來,查詢緩存需要打開相關類的class緩存。list和iterate方法第一次執行的時候,都是既填充查詢緩存又填充class緩存的。這里還有一個很容易被忽視的重要問題,即打開查詢緩存以後,即使是list方法也可能遇到1+N的問題!相同條件第一次list的時候,因為查詢緩存中找不到,不管class緩存是否存在數據,總是發送一條sql語句到資料庫獲取全部數據,然後填充查詢緩存和class緩存。但是第二次執行的時候,問題就來了,如果你的class緩存的超時時間比較短,現在class緩存都超時了,但是查詢緩存還在,那麼list方法在獲取id串以後,將會一個一個去資料庫load!因此,class緩存的超時時間一定不能短於查詢緩存設置的超時時間!如果還設置了發呆時間的話,保證class緩存的發呆時間也大於查詢的緩存的生存時間。這里還有其他情況,比如class緩存被程序強制evict了,這種情況就請自己注意了。另外,如果hql查詢包含select字句,那麼查詢緩存裡面的value就是整個結果集了。當hibernate更新資料庫的時候,它怎麼知道更新哪些查詢緩存呢?hibernate在一個地方維護每個表的最後更新時間,其實也就是放在上面net.sf.hibernate.cache.UpdateTimestampsCache所指定的緩存配置裡面。當通過hibernate更新的時候,hibernate會知道這次更新影響了哪些表。然後它更新這些表的最後更新時間。每個緩存都有一個生成時間和這個緩存所查詢的表,當hibernate查詢一個緩存是否存在的時候,如果緩存存在,它還要取出緩存的生成時間和這個緩存所查詢的表,然後去查找這些表的最後更新時間,如果有一個表在生成時間後更新過了,那麼這個緩存是無效的。可以看出,只要更新過一個表,那麼凡是涉及到這個表的查詢緩存就失效了,因此查詢緩存的命中率可能會比較低。Collection緩存需要在hbm的collection裡面設置假如class是Cat,collection叫children,那麼ehcache裡面配置Collection的緩存和前面查詢緩存的list一樣,也是只保持一串id,但它不會因為這個表更新過就失效,一個collection緩存僅在這個collection裡面的元素有增刪時才失效。這樣有一個問題,如果你的collection是根據某個欄位排序的,當其中一個元素更新了該欄位時,導致順序改變時,collection緩存裡面的順序沒有做更新。緩存策略只讀緩存(read-only):沒有什麼好說的讀/寫緩存(read-write):程序可能要的更新數據不嚴格的讀/寫緩存(nonstrict-read-write):需要更新數據,但是兩個事務更新同一條記錄的可能性很小,性能比讀寫緩存好事務緩存(transactional):緩存支持事務,發生異常的時候,緩存也能夠回滾,只支持jta環境,這個我沒有怎麼研究過讀寫緩存和不嚴格讀寫緩存在實現上的區別在於,讀寫緩存更新緩存的時候會把緩存裡面的數據換成一個鎖,其他事務如果去取相應的緩存數據,發現被鎖住了,然後就直接取資料庫查詢。在hibernate2.1的ehcache實現中,如果鎖住部分緩存的事務發生了異常,那麼緩存會一直被鎖住,直到60秒後超時。不嚴格讀寫緩存不鎖定緩存中的數據。使用二級緩存的前置條件你的hibernate程序對資料庫有獨占的寫訪問權,其他的進程更新了資料庫,hibernate是不可能知道的。你操作資料庫必需直接通過hibernate,如果你調用存儲過程,或者自己使用jdbc更新資料庫,hibernate也是不知道的。hibernate3.0的大批量更新和刪除是不更新二級緩存的,但是據說3.1已經解決了這個問題。這個限制相當的棘手,有時候hibernate做批量更新、刪除很慢,但是你卻不能自己寫jdbc來優化,很郁悶吧。SessionFactory也提供了移除緩存的方法,你一定要自己寫一些JDBC的話,可以調用這些方法移除緩存,這些方法是:voidevict(ClasspersistentClass)Evictallentriesfromthesecond-levelcache.voidevict(ClasspersistentClass,Serializableid)Evictanentryfromthesecond-levelcache.voidevictCollection(StringroleName)Evictallentriesfromthesecond-levelcache.voidevictCollection(StringroleName,Serializableid)Evictanentryfromthesecond-levelcache.voidevictQueries().voidevictQueries(StringcacheRegion).不過我不建議這樣做,因為這樣很難維護。比如你現在用JDBC批量更新了某個表,有3個查詢緩存會用到這個表,用evictQueries(StringcacheRegion)移除了3個查詢緩存,然後用evict(ClasspersistentClass)移除了class緩存,看上去好像完整了。不過哪天你添加了一個相關查詢緩存,可能會忘記更新這里的移除代碼。如果你的jdbc代碼到處都是,在你添加一個查詢緩存的時候,還知道其他什麼地方也要做相應的改動嗎?----------------------------------------------------總結:不要想當然的以為緩存一定能提高性能,僅僅在你能夠駕馭它並且條件合適的情況下才是這樣的。hibernate的二級緩存限制還是比較多的,不方便用jdbc可能會大大的降低更新性能。在不了解原理的情況下亂用,可能會有1+N的問題。不當的使用還可能導致讀出臟數據。如果受不了hibernate的諸多限制,那麼還是自己在應用程序的層面上做緩存吧。在越高的層面上做緩存,效果就會越好。就好像盡管磁碟有緩存,資料庫還是要實現自己的緩存,盡管資料庫有緩存,咱們的應用程序還是要做緩存。因為底層的緩存它並不知道高層要用這些數據干什麼,只能做的比較通用,而高層可以有針對性的實現緩存,所以在更高的級別上做緩存,效果也要好些吧。參考資料:/topic/18904
❽ 如何制定Redis過期策略
Redis是key-value資料庫,我們可以設置Redis中緩存的key的過期時間。Redis的過期策略就是指當Redis中緩存的key過期了,Redis如何處理。
過期策略通常有以下三種:
定時過期:每個設置過期時間的key都需要創建一個定時器,到過期時間就會立即清除。該策略可以立即清除過期的數據,對內存很友好;但是會佔用大量的CPU資源去處理過期的數據,從而影響緩存的響應時間和吞吐量。
惰性過期:只有當訪問一個key時,才會判斷該key是否已過期,過期則清除。該策略可以最大化地節省CPU資源,卻對內存非常不友好。極端情況可能出現大量的過期key沒有再次被訪問,從而不會被清除,佔用大量內存。
定期過期:每隔一定的時間,會掃描一定數量的資料庫的expires字典中一定數量的key,並清除其中已過期的key。該策略是前兩者的一個折中方案。通過調整定時掃描的時間間隔和每次掃描的限定耗時,可以在不同情況下使得CPU和內存資源達到最優的平衡效果。
(expires字典會保存所有設置了過期時間的key的過期時間數據,其中,key是指向鍵空間中的某個鍵的指針,value是該鍵的毫秒精度的UNIX時間戳表示的過期時間。鍵空間是指該Redis集群中保存的所有鍵。)
❾ 網頁緩存的生命周期是多少
有很多理由去解釋理解ASP.NET頁面生命周期是非常重要的,主要是要去理解什麼地方放置什麼特定的方法,什麼時候我們應該設置什麼相關的屬性。如果去開發自定義的伺服器控制項,理解生命周期對糾正控制項初始化時候的錯誤,以及使用view-state和後台代碼設置屬性是非常有用的。(控制項事件只與ASP.NET頁面相關)
頁面生命周期要看它是否是第一次請求,還是回發(本身頁面請求),最後決定是否到Web伺服器。當一個網頁被Web伺服器請求時,在回發到web瀏覽器之前,會經過一系列步驟/事件(如初始化,控制項實例化,state的恢復和保存,執行事件處理代碼,渲染)。
如果我們正確地使用和操作頁面生命周期事件,它對web應用程序開發會是一個非常方便和強大的工具。
❿ 如何有效實現依賴Oracle的緩存策略
ASP.NET 中的緩存提供了對SQL依賴項的支持,也就是說當SQL SERVER資料庫中的表或行中的數據被更改後,緩存中的頁面就失效,否則,頁面輸出可一直保留在緩存當中。這確實為程序員提供了方便。但微軟一向很小家子氣,只為使用自家產品SQL SERVER的程序員提供了方便,那些用Oracle資料庫的ASP.NET程序員怎麼辦呢?
其實不用著急,因為ASP.NET中的緩存還提供了對文件依賴項的支持,也就是緩存依賴於某個文件,該文件被修改後,緩存中的頁面就失效。只要巧妙利用ASP.NET的文件依賴項緩存策略和Oracle中的觸發器,就可輕松實現依賴Oracle的緩存策略。思路很簡單,先將頁面的緩存策略設置為依賴某一個文件,再為Oracle中需要依賴的表添加一個觸發器,當表中的數據被更改時,修改緩存所依賴的文件中的內容。
下面以一個小例子來具體說明:
試驗目的:Default.aspx頁面的緩存依賴於Oracle資料庫中SCOTT用戶的DEPT表,該表中數據被更改後,緩存中的頁面失效。緩存的過期時間為120秒。
一、設置網站頁面的緩存依賴於文件TextFile.txt詳見System.Web.Caching.Cache類 Asp.NET緩存 各種緩存依賴二、在Oracle資料庫中創建觸發器
1、觸發器被觸發時執行PL/SQL代碼塊。PL/SQL代碼塊直接讀寫操作系統中的文件,需調用內置的utl_file程序包。這需要先修改Oracle的初始化參數文件INIT.ORA,在其中添加參數utl_file_dir,來指定文件的目錄。修改INIT.ORA文件後,需重啟Oracle資料庫,設置的參數才能生效。
在INIT.ORA文件中添加下面一行內容:
utl_file_dir='E:/CSharp/CacheByOracleDependncy'
也可以設置為utl_file_dir=*,不指定具體目錄,即任何目錄都可以。
如果是Oracle 9i資料庫,還有一種方法也能起到同樣的作用:在sys用戶下創建一個directory目錄(實際上是在sys用戶下的dir$表中增加一個對應的OS_PATH),然後將對該directory對象的讀/寫操作的許可權grant給public。
[sql] view plain
create or replace directory FILEPATH as 'E:/CSharp/CacheByOracleDependncy';grant read on directory FILEPATH to public;這里我使用的是第二種方法。
2、為所依賴的表(SCOTT用戶的DEPT表)創建一個觸發器:當DEPT表中的數據更改後,觸發器就會將當前系統時間寫入TextFile.txt文件中。
[sql] view plain
CREATE OR REPLACE TRIGGER
"SCOTT"."TEST_CACHE_BY_ORACLE_DEPENDNCY" AFTERINSERT
OR UPDATE
OR DELETE OF "DEPTNO", "DNAME", "LOC" ON "SCOTT"."DEPT" DECLAREfile_handle utl_file.file_type;
BEGIN
--打開文件
file_handle := utl_file.fopen('FILEPATH','TextFile.txt','w');--將當前系統時間寫入文件
IF utl_file.is_open(file_handle) THEN
utl_file.put_line(file_handle,to_char(SYSDATE,'yyyy-mm-dd hh24:mi:ss'));END IF;
--關閉文件
utl_file.fclose(file_handle);
EXCEPTION
WHEN OTHERS THEN
BEGIN
IF utl_file.is_open(file_handle) THEN
utl_file.fclose(file_handle);
END IF;
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
END;
如果應用伺服器和資料庫伺服器不是同一台伺服器可能會遇到項目無法成功訪問文件進行依賴的情況:
解決方法詳見ASP.Net訪問網路驅動器(映射磁碟)