Hibernate 二级缓存
生活随笔
收集整理的這篇文章主要介紹了
Hibernate 二级缓存
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
Hibernate 緩存
?緩存(Cache): 計算機領域非常通用的概念。它介于應用程序和永久性數(shù)據(jù)存儲源(如硬盤上的文件或者數(shù)據(jù)庫)之間,其作用是降低應用程序直接讀寫永久性數(shù)據(jù)存儲源的頻率,從而提高應用的運行性能。緩存中的數(shù)據(jù)是數(shù)據(jù)存儲源中數(shù)據(jù)的拷貝。緩存的物理介質通常是內存 ?Hibernate中提供了兩個級別的緩存 –第一級別的緩存是 Session 級別的緩存,它是屬于事務范圍的緩存。這一級別的緩存由 hibernate 管理的 –第二級別的緩存是 SessionFactory 級別的緩存,它是屬于進程范圍的緩存 SessionFactory 級別的緩存 ?SessionFactory 的緩存可以分為兩類: –內置緩存: Hibernate 自帶的, 不可卸載. 通常在 Hibernate 的初始化階段, Hibernate 會把映射元數(shù)據(jù)和預定義的 SQL 語句放到 SessionFactory 的緩存中, 映射元數(shù)據(jù)是映射文件中數(shù)據(jù)(.hbm.xml 文件中的數(shù)據(jù))的復制. 該內置緩存是只讀的. –外置緩存(二級緩存): 一個可配置的緩存插件. 在默認情況下, SessionFactory 不會啟用這個緩存插件. 外置緩存中的數(shù)據(jù)是數(shù)據(jù)庫數(shù)據(jù)的復制, 外置緩存的物理介質可以是內存或硬盤 使用 Hibernate 的二級緩存 ?適合放入二級緩存中的數(shù)據(jù): –很少被修改 –不是很重要的數(shù)據(jù), 允許出現(xiàn)偶爾的并發(fā)問題 ?不適合放入二級緩存中的數(shù)據(jù): –經常被修改 –財務數(shù)據(jù), 絕對不允許出現(xiàn)并發(fā)問題 –與其他應用程序共享的數(shù)據(jù) 二級緩存的并發(fā)訪問策略 ?兩個并發(fā)的事務同時訪問持久層的緩存的相同數(shù)據(jù)時, 也有可能出現(xiàn)各類并發(fā)問題. ?二級緩存可以設定以下 4 種類型的并發(fā)訪問策略, 每一種訪問策略對應一種事務隔離級別 –非嚴格讀寫(Nonstrict-read-write): 不保證緩存與數(shù)據(jù)庫中數(shù)據(jù)的一致性. 提供 Read Uncommited 事務隔離級別, 對于極少被修改, 而且允許臟讀的數(shù)據(jù), 可以采用這種策略 –讀寫型(Read-write): 提供 Read Commited 數(shù)據(jù)隔離級別.對于經常讀但是很少被修改的數(shù)據(jù), 可以采用這種隔離類型, 因為它可以防止臟讀 –事務型(Transactional): 僅在受管理環(huán)境下適用. 它提供了 Repeatable Read 事務隔離級別. 對于經常讀但是很少被修改的數(shù)據(jù), 可以采用這種隔離類型, 因為它可以防止臟讀和不可重復讀 –只讀型(Read-Only):提供 Serializable 數(shù)據(jù)隔離級別, 對于從來不會被修改的數(shù)據(jù), 可以采用這種訪問策略 管理 Hibernate 的二級緩存 ?Hibernate 的二級緩存是進程或集群范圍內的緩存 ?二級緩存是可配置的的插件, Hibernate 允許選用以下類型的緩存插件: –EHCache: 可作為進程范圍內的緩存, 存放數(shù)據(jù)的物理介質可以使內存或硬盤, 對 Hibernate 的查詢緩存提供了支持 –OpenSymphony OSCache:可作為進程范圍內的緩存, 存放數(shù)據(jù)的物理介質可以使內存或硬盤, 提供了豐富的緩存數(shù)據(jù)過期策略, 對 Hibernate 的查詢緩存提供了支持 –SwarmCache: 可作為集群范圍內的緩存, 但不支持 Hibernate 的查詢緩存 –JBossCache:可作為集群范圍內的緩存, 支持 Hibernate 的查詢緩存 ?4 種緩存插件支持的并發(fā)訪問策略(x 代表支持, 空白代表不支持) 配置進程范圍內的二級緩存 ?配置進程范圍內的二級緩存的步驟: –選擇合適的緩存插件: EHCache(jar 包和 配置文件), 并編譯器配置文件 –在 Hibernate 的配置文件中啟用二級緩存并指定和 EHCache 對應的緩存適配器 –選擇需要使用二級緩存的持久化類, 設置它的二級緩存的并發(fā)訪問策略 ?<class> 元素的 cache 子元素表明 Hibernate 會緩存對象的簡單屬性, 但不會緩存集合屬性, 若希望緩存集合屬性中的元素, 必須在 <set> 元素中加入 <cache> 子元素 ?在 hibernate 配置文件中通過 <class-cache/> 節(jié)點配置使用緩存 ehcache.xml ?<diskStore>: 指定一個目錄:當 EHCache 把數(shù)據(jù)寫到硬盤上時, 將把數(shù)據(jù)寫到這個目錄下. ?<defaultCache>: 設置緩存的默認數(shù)據(jù)過期策略 ?<cache> 設定具體的命名緩存的數(shù)據(jù)過期策略。每個命名緩存代表一個緩存區(qū)域 ?緩存區(qū)域(region):一個具有名稱的緩存塊,可以給每一個緩存塊設置不同的緩存策略。如果沒有設置任何的緩存區(qū)域,則所有被緩存的對象,都將使用默認的緩存策略。即:<defaultCache.../> ?Hibernate在不同的緩存區(qū)域保存不同的類/集合。 –對于類而言,區(qū)域的名稱是類名。如:com.atguigu.domain.Customer –對于集合而言,區(qū)域的名稱是類名加屬性名。如com.atguigu.domain.Customer.orders ?cache 元素的屬性?? –name:設置緩存的名字,它的取值為類的全限定名或類的集合的名字 –maxInMemory:設置基于內存的緩存中可存放的對象最大數(shù)目 –eternal:設置對象是否為永久的,true表示永不過期,此時將忽略timeToIdleSeconds 和 timeToLiveSeconds屬性; 默認值是false –timeToIdleSeconds:設置對象空閑最長時間,以秒為單位, 超過這個時間,對象過期。當對象過期時,EHCache會把它從緩存中清除。如果此值為0,表示對象可以無限期地處于空閑狀態(tài)。 –timeToLiveSeconds:設置對象生存最長時間,超過這個時間,對象過期。如果此值為0,表示對象可以無限期地存在于緩存中. 該屬性值必須大于或等于 timeToIdleSeconds 屬性值 –overflowToDisk:設置基于內存的緩存中的對象數(shù)目達到上限后,是否把溢出的對象寫到基于硬盤的緩存中? 查詢緩存 ?對于經常使用的查詢語句, 如果啟用了查詢緩存, 當?shù)谝淮螆?zhí)行查詢語句時, Hibernate 會把查詢結果存放在查詢緩存中. 以后再次執(zhí)行該查詢語句時, 只需從緩存中獲得查詢結果, 從而提高查詢性能 ?查詢緩存使用于如下場合: –應用程序運行時經常使用查詢語句 –很少對與查詢語句檢索到的數(shù)據(jù)進行插入, 刪除和更新操作 ?啟用查詢緩存的步驟 –配置二級緩存, 因為查詢緩存依賴于二級緩存 –在 hibernate 配置文件中啟用查詢緩存 –對于希望啟用查詢緩存的查詢語句, 調用 Query 的 setCacheable() 方法 時間戳緩存區(qū)域 ?時間戳緩存區(qū)域存放了對于查詢結果相關的表進行插入, 更新或刪除操作的時間戳.? Hibernate 通過時間戳緩存區(qū)域來判斷被緩存的查詢結果是否過期, 其運行過程如下: –T1 時刻執(zhí)行查詢操作, 把查詢結果存放在 QueryCache 區(qū)域, 記錄該區(qū)域的時間戳為 T1 –T2 時刻對查詢結果相關的表進行更新操作, Hibernate 把 T2 時刻存放在 UpdateTimestampCache 區(qū)域. –T3 時刻執(zhí)行查詢結果前, 先比較 QueryCache 區(qū)域的時間戳和 UpdateTimestampCache 區(qū)域的時間戳, 若 T2 >T1, 那么就丟棄原先存放在 QueryCache 區(qū)域的查詢結果, 重新到數(shù)據(jù)庫中查詢數(shù)據(jù), 再把結果存放到 QueryCache 區(qū)域; 若 T2 < T1, 直接從 QueryCache 中獲得查詢結果 Query 接口的 iterate() 方法 ?Query 接口的 iterator() 方法 –同 list() 一樣也能執(zhí)行查詢操作 –list() 方法執(zhí)行的 SQL 語句包含實體類對應的數(shù)據(jù)表的所有字段 –Iterator() 方法執(zhí)行的SQL 語句中僅包含實體類對應的數(shù)據(jù)表的 ID 字段 –當遍歷訪問結果集時, 該方法先到 Session 緩存及二級緩存中查看是否存在特定 OID 的對象, 如果存在, 就直接返回該對象, 如果不存在該對象就通過相應的 SQL Select 語句到數(shù)據(jù)庫中加載特定的實體對象 ?大多數(shù)情況下, 應考慮使用 list() 方法執(zhí)行查詢操作. iterator() 方法僅在滿足以下條件的場合, 可以稍微提高查詢性能: –要查詢的數(shù)據(jù)表中包含大量字段 –啟用了二級緩存, 且二級緩存中可能已經包含了待查詢的對象 管理 Session ?Hibernate? 自身提供了三種管理 Session 對象的方法 –Session 對象的生命周期與本地線程綁定 –Session 對象的生命周期與 JTA 事務綁定 –Hibernate 委托程序管理 Session 對象的生命周期 ?在 Hibernate 的配置文件中, hibernate.current_session_context_class 屬性用于指定 Session 管理方式, 可選值包括 –thread: Session 對象的生命周期與本地線程綁定 –jta*: Session 對象的生命周期與 JTA 事務綁定 managed: Hibernate 委托程序來管理 Session?對象的生命周期 Session 對象的生命周期與本地線程綁定 ?如果把 Hibernate 配置文件的 hibernate.current_session_context_class 屬性值設為 thread, Hibernate 就會按照與本地線程綁定的方式來管理 Session ?Hibernate 按一下規(guī)則把 Session 與本地線程綁定 –當一個線程(threadA)第一次調用 SessionFactory 對象的 getCurrentSession() 方法時, 該方法會創(chuàng)建一個新的 Session(sessionA) 對象, 把該對象與 threadA 綁定, 并將 sessionA 返回 –當 threadA 再次調用 SessionFactory 對象的 getCurrentSession() 方法時, 該方法將返回 sessionA 對象 –當 threadA 提交 sessionA 對象關聯(lián)的事務時, Hibernate 會自動flush sessionA 對象的緩存, 然后提交事務, 關閉 sessionA 對象. 當 threadA 撤銷 sessionA 對象關聯(lián)的事務時, 也會自動關閉 sessionA 對象 –若 threadA 再次調用 SessionFactory 對象的 getCurrentSession() 方法時, 該方法會又創(chuàng)建一個新的 Session(sessionB) 對象, 把該對象與 threadA 綁定, 并將 sessionB 返回? 批量處理數(shù)據(jù) ?批量處理數(shù)據(jù)是指在一個事務中處理大量數(shù)據(jù). ?在應用層進行批量操作, 主要有以下方式: –通過 Session –通過 HQL –通過 StatelessSession –通過 JDBC API 通過 Session 來進行批量操作 ?Session 的 save() 及 update() 方法都會把處理的對象存放在自己的緩存中. 如果通過一個 Session 對象來處理大量持久化對象, 應該及時從緩存中清空已經處理完畢并且不會再訪問的對象. 具體的做法是在處理完一個對象或小批量對象后, 立即調用 flush() 方法刷新緩存, 然后在調用 clear() 方法清空緩存 ?通過 Session 來進行處理操作會受到以下約束 –需要在? Hibernate 配置文件中設置 JDBC 單次批量處理的數(shù)目, 應保證每次向數(shù)據(jù)庫發(fā)送的批量的 SQL 語句數(shù)目與 batch_size 屬性一致 –若對象采用 “identity” 標識符生成器, 則 Hibernate 無法在 JDBC 層進行批量插入操作 –進行批量操作時, 建議關閉 Hibernate 的二級緩存 ?批量插入數(shù)據(jù): Person person = null; for(int i = 0; i < 100000; i++){Person p = new Person();p.setName("--"+i);session.save(p);if((i+1)%20 == 0){session.flush();session.clear();} }
?
?批量更新: 在進行批量更新時, 如果一下子把所有對象都加載到 Session 緩存, 然后再緩存中一一更新, 顯然是不可取的 ?使用可滾動的結果集 org.hibernate.ScrollableResults, 該對象中實際上并不包含任何對象, 只包含用于在線定位記錄的游標. 只有當程序遍歷訪問 ScrollableResults 對象的特定元素時, 它才會到數(shù)據(jù)庫中加載相應的對象. ?org.hibernate.ScrollableResults 對象由 Query 的 scroll 方法返回 ScrollableResults sr = session.createQuery("from Person ").scroll();int count = 0;while(sr.next()){Person person = (Person) sr.get(0);person.setName(person.getName()+"****");if(((count++)+1)%100==0){session.flush();session.clear();}}通過 HQL 來進行批量操作
?注意: HQL 只支持 INSERT INTO … SELECT 形式的插入語句, 但不支持 INSERT INTO … VALUES 形式的插入語句. 所以使用 HQL 不能進行批量插入操作.? 通過StatelessSession來進行批量操作 ?從形式上看,StatelessSession與session的用法類似。StatelessSession與session相比,有以下區(qū)別: –StatelessSession沒有緩存,通過StatelessSession來加載、保存或更新后的對象處于游離狀態(tài)。 –StatelessSession不會與Hibernate的第二級緩存交互。 –當調用StatelessSession的save()、update()或delete()方法時,這些方法會立即執(zhí)行相應的SQL語句,而不會僅計劃執(zhí)行一條SQL語句 –StatelessSession不會進行臟檢查,因此修改了Customer對象屬性后,還需要調用StatelessSession的update()方法來更新數(shù)據(jù)庫中數(shù)據(jù)。 –StatelessSession不會對關聯(lián)的對象進行任何級聯(lián)操作。 –通過同一個StatelessSession對象兩次加載OID為1的Customer對象,得到的兩個對象內存地址不同。 –StatelessSession所做的操作可以被Interceptor攔截器捕獲到,但是會被Hibernate的事件處理系統(tǒng)忽略掉。轉載于:https://www.cnblogs.com/fengyexjtu/p/5123107.html
總結
以上是生活随笔為你收集整理的Hibernate 二级缓存的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用PhantomJS实现网页截图服务
- 下一篇: mvc 下拉框赋值