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