1. 程式人生 > >hibernate 1、2級快取

hibernate 1、2級快取

快取是資料庫資料在記憶體中的臨時容器,它包含了庫表資料在記憶體中的拷貝,位於資料庫與資料訪問層之間。對於查詢操作相當頻繁的系統(論壇,新聞釋出等),良好的快取機制顯得尤為重要。
ORM在進行資料讀取時,首先在快取中查詢,避免了資料庫呼叫的效能開銷。
ORM的資料快取應包含下面幾個層次:
1)事務級快取 2)應用級快取 3)分散式快取

具體針對Hibernate而言,採用兩級快取策略,其過程描述:
(1)條件查詢的時候,總是發出一條select * from table_name where …. 這樣的SQL語句查詢資料庫,一次獲得所有的資料物件。
(2) 把獲得的所有資料物件根據ID放入到第二級快取中。
(3) 當Hibernate根據ID訪問資料物件的時候,首先從Session一級快取中查;查不到,如果配置了二級快取,那麼從二級快取中查;查不到,再查詢資料庫,把結果按照ID放入到快取。
(4) 刪除、更新、增加資料的時候,同時更新快取。
1. 一級快取(session level)-資料庫事務級快取

 1)根據主鍵id載入資料時。 Session.load(), Session.iterate()方法

  2)延遲載入時

   Session內部維護一個數據物件集合,包括了本Session內選取的、操作的資料物件。這稱為Session內部快取,是Hibernate的第一級最快快取,屬於Hibernate的既定行為,不需要進行配置(也沒有辦法配置 :-)。

   內部快取正常情況下由hibernate自動維護,但也可人工干預:
              1) Session.evict (): 將某個特定物件從內部快取中清除
               2)Session.clear(): 清空內部快取

2.二級快取(SessionFactory level)-應用級快取

   二級快取由SessionFactory的所有session例項共享。
  1. 第三方快取實現(二級快取)
    常用的二級快取外掛

**EHCache org.hibernate.cache.EhCacheProvider
OSCache org.hibernate.cache.OSCacheProvider**

**SwarmCahe org.hibernate.cache.SwarmCacheProvider
JBossCache org.hibernate.cache.TreeCacheProvider**

hibernate批量查詢引起的記憶體溢位問題

  批量查詢基本不適合使用現有的持久層技術來做,如CMP或hibernate,IBatis倒是可以.

  因為每次呼叫Session.save()方法時,當前session都會將物件納入到自身的內部快取中。內部快取不同於二級快取,我們可以在二級快取的配置中指定其最大容量。

解決方案:

1)在批處理情況下,關閉Hibernate快取,如果關閉Hibernate快取,那麼和直接使用JDBC就沒有區別。

2) 每隔一段時間清空Session內部快取

 Session實現了非同步write-behind,它允許Hibernate顯式地寫操作的批處理。 這裡,我給出Hibernate如何實現批量插入的方法: 首先,我們設定一個合理的JDBC批處理大小,hibernate.jdbc.batch_size 20。 然後在一定間隔對Session進行flush()和clear()。
Session session = sessionFactory.openSession(); 
Transaction tx = session.beginTransaction(); 
for ( int i=0; i<100000; i++ ) {
Customer customer = new Customer(.....); 
session.save(customer); 
if ( i % 20 == 0 ) {
//flush 插入資料和釋放記憶體: 
session.flush(); session.clear(); } 
} 
tx.commit(); 
session.close();

     為了優化效能,可執行批量操作。在傳統的JDBC程式設計中,批量操作方式如下,將數個SQL操作批量提交:

PrepareStatement  ps=conn.prepareStatement("insert into users(name) values(?)");   
for(int i=0;i<100000;i++){
     ps.setString(1, "user"+i);
     ps.addBatch();
} 
int[] counts=ps.executeBatch

  在Hibernate中,可以設定hibernate.jdbc.batch_size 引數來指定每次提交的sql數量。

hibernate2和hibernate3資料批量刪除機制分析

1.hibernate2

        Transaction tx=session.beginTransaction();
        session.delete("from users");
        tx.commit();

     觀察日誌輸出:

select ... from users
Hibernate:delete from users where id=?
Hibernate:delete from users where id=?
Hibernate:delete from users where id=?
...

       hibernate2版本會首先從資料庫中查詢出所有符合條件的記錄,再對此記錄迴圈刪除。如果記錄量過大,勢必引起記憶體溢位和刪除效率問題。ORM為什麼要這麼做呢?因為ORM為了自動維護記憶體狀態,必須知道使用者到底對哪些資料進行了操作。問題的解決方法:

1)記憶體消耗

       批量刪除前首先從資料庫中查詢出所有符合條件的記錄,如果資料量過大,就會導致 OutOfMemoryError.

        可以採用Session .iterate或Query.iterate方法逐條獲取記錄,再執行delete操作。另外,hibernate2.16後的版本提供了基於遊標的資料遍歷操作:

Transaction tx=session.beginTransaction();
String hql="from users";
Query query=session.createQrery(hql);
ScrollableResults sr=query.scroll();
while(sr.next()){
  TUser user=(TUser)sr.get(0);
  session.delete();
}
tx.commit();
2)迴圈刪除的效率問題
     由於hibernate在批量刪除操作過程中,需要反覆呼叫delete SQL,存在效能問題。我們仍然可以通過調整hibernate.jdbc.batch_size引數來解決。
2.hibernate3
    hibernate3 HQL中引入了 bulk delete/update操作, 即通過一條獨立的sql語句來完成資料的批量操作。

Transaction tx=session.beginTransaction();
String hql="delete TUser";
Query query=session.createQrery(hql);
int count=query.executeUpdate();
tx.commit();
觀察日誌輸出:
Hibernate:delete from TUser

(二)ibatis資料快取
    相對Hibernate 等封裝較為嚴密的ORM 實現而言(因為對資料物件的操作實現了較為嚴密的封裝,可以保證其作用範圍內的快取同步,而ibatis 提供的是半封閉的封裝實現,因此對快取的操作難以做到完全的自動化同步)。    ibatis 的快取機制使用必須特別謹慎。特別是flushOnExecute 的設定(見“ibatis配置”一節中的相關內容),需要考慮到所有可能引起實際資料與快取資料不符的操作。如本模組中其他Statement對資料的更新,其他模組對資料的更新,甚至第三方系統對資料的更新。否則,髒資料的出現將為系統的正常執行造成極大隱患。如果不能完全確定資料更新操作的波及範圍,建議避免Cache的盲目使用。
1.iBatis cache設定
sqlmap-config.xml在<sqlMapConfig>裡面加入
<settings
   cacheModelsEnabled="true"
   enhancementEnabled="true"
    lazyLoadingEnabled="true" />
maps.xml在<sqlMap>裡面加入
<cacheModel   id="userCache"   type="LRU"   readonly="true"   serialize="false">
       <flushInterval hours="24"/>
      <flushOnExecute statement="insertTest"/>
      <property name="size" value="1000" />
</cacheModel>
可以看到,Cache有如下幾個比較重要的屬性:readOnly,serialize,type
readOnly
     readOnly值的是快取中的資料物件是否只讀。這裡的只讀並不是意味著資料物件一
旦放入快取中就無法再對資料進行修改。而是當資料物件發生變化的時候,如資料對
象的某個屬性發生了變化,則此資料物件就將被從快取中廢除,下次需要重新從資料
庫讀取資料,構造新的資料物件。
serialize
   如果需要全域性的資料快取,CacheModel的serialize屬性必須被設為true。否則資料快取只對當前Session(可簡單理解為當前執行緒)有效,區域性快取對系統的整體效能提升有限。
Cache Type:
    與hibernate類似,ibatis通過緩衝介面的外掛式實現,提供了多種Cache的實現機制可供選擇:
1. MEMORY
2. LRU
3. FIFO
4. OSCACHE
MEMORY型別Cache與WeakReference
        MEMORY 型別的Cache 實現,實際上是通過Java 物件引用進行。ibatis 中,其實現類
為com.ibatis.db.sqlmap.cache.memory.MemoryCacheController,MemoryCacheController 內部,
使用一個HashMap來儲存當前需要快取的資料物件的引用。

LRU型Cache
        當Cache達到預先設定的最大容量時,ibatis會按照“最少使用”原則將使用頻率最少
的物件從緩衝中清除。可配置的引數有:
flushInterval:指定了多長時間清除快取,上例中指定每24小時強行清空快取區的所有內容。
size
FIFO型Cache
先進先出型快取,最先放入Cache中的資料將被最先廢除。
(三)開源資料快取策略OSCache

可以解決的問題:

1)資訊系統中需要處理的基礎資料的內容短時間內是不會發生變化的,但是在一個相對長一些的時間裡,它卻可能是動態增加或者減少的。

2)統計報表是一個週期性的工作,可能是半個月、一個月或者更長的時間才會需要更新一次,然而統計報表通常是圖形顯示或者是生成pdf、word、excel等格式的檔案,這些圖形內容、檔案的生成通常需要消耗很多的系統資源,給系統執行造成很大的負擔。

        OSCache是OpenSymphony組織提供的一個J2EE架構中Web應用層的快取技術實現元件。OSCache支援對部分頁面內容或者對頁面級的響應內容進行快取,程式設計者可以根據不同的需求、不同的環境選擇不同的快取級別。可以使用記憶體、硬碟空間、同時使用記憶體和硬碟或者提供自己的其他資源(需要自己提供介面卡)作為快取區。

使用步驟:

1. 下載、解壓縮OSCache

請到OSCache的主頁http://www.opensymphony.com/oscache/download.html下載Oscache的最新版本,作者下載的是OSCache的最新穩定版本2.0。

將下載後的。Zip檔案解壓縮到c:\oscache(後面的章節中將使用%OSCache_Home%來表示這個目錄)目錄下

2. 新建立一個web應用

3. 將主要元件%OSCache_Home%\oscache.jar放入WEB-INF\lib目錄

4. commons-logging.jar、commons-collections.jar的處理

OSCache元件用Jakarta Commons Logging來處理日誌資訊,所以需要commons-logging.jar的支援,請將%OSCache_Home%\lib\core\commons-logging.jar放入classpath(通常意味著將這個檔案放入WEB-INF\lib目錄) 
如果使用JDK1.3,請將%OSCache_Home%\lib\core\commons-collections.jar放入classpath,如果使用JDK1.4或者以上版本,則不需要了 
5. 將oscache.properties、oscache.tld放入WEB-INF\class目錄

%OSCache_Home%\oscache.properties包含了對OSCache執行特徵值的設定資訊 
%OSCache_Home%\oscache.tld包含了OSCache提供的標籤庫的定義內容 
6. 修改web.xml檔案

在web.xml檔案中增加下面的內容,增加對OSCache提供的taglib的支援:

<taglib>
<taglib-uri>oscache</taglib-uri>
<taglib-location>/WEB-INF/classes/oscache.tld</taglib-location>
</taglib>

7.最簡單的cache標籤用法

使用預設的關鍵字來標識cache內容,超時時間是預設的3600<cache:cache>
<%
//自己的JSP程式碼內容
%>
</cache:cache>

8. 快取單個檔案

         在OSCache元件中提供了一個CacheFilter用於實現頁面級的快取,主要用於對web應用中的某些動態頁面進行快取,尤其是那些需要生成pdf格式檔案/報表、圖片檔案等的頁面,不僅減少了資料庫的互動、減少資料庫伺服器的壓力,而且對於減少web伺服器的效能消耗有很顯著的效果。

修改web.xml,增加如下內容,確定對/testContent.jsp頁面進行快取。

<filter>
      <filter-name>CacheFilter</filter-name>
<filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CacheFilter</filter-name>
<!-對/testContent.jsp頁面內容進行快取-->
      <url-pattern>/testContent.jsp</url-pattern>
</filter-mapping>