hibernate緩存的作用
㈠ hibernate緩存機制有什麼好處
緩存的介質一般是內存,所以讀寫速度很快。但如果緩存中存放的數據量非常大時,也會用硬碟作為緩存介質。緩存的實現不僅僅要考慮存儲的介質,還要考慮到管理緩存的並發訪問和緩存數據的生命周期。
Hibernate的緩存包括Session的緩存和SessionFactory的緩存,其中SessionFactory的緩存又可以分為兩類:內置緩存和外置緩存。Session的緩存是內置的,不能被卸載,也被稱為Hibernate的第一級緩存。SessionFactory的內置緩存和Session的緩存在實現方式上比較相似,前者是SessionFactory對象的一些集合屬性包含的數據,後者是指Session的一些集合屬性包含的數據。SessionFactory的內置緩存中存放了映射元數據和預定義sql語句,映射元數據是映射文件中數據的拷貝,而預定義SQL語句是在Hibernate初始化階段根據映射元數據推導出來,SessionFactory的內置緩存是只讀的,應用程序不能修改緩存中的映射元數據和預定義SQL語句,因此SessionFactory不需要進行內置緩存與映射文件的同步。SessionFactory的外置緩存是一個可配置的插件。在默認情況下,SessionFactory不會啟用這個插件。外置緩存的數據是資料庫數據的拷貝,外置緩存的介質可以是內存或者硬碟。SessionFactory的外置緩存也被稱為Hibernate的第二級緩存。
Hibernate的這兩級緩存都位於持久化層,存放的都是資料庫數據的拷貝,為了理解二者的區別,需要深入理解持久化層的緩存的兩個特性:緩存的范圍和緩存的並發訪問策略。
㈡ Hibernate的緩存技術有哪些
緩存是資料庫數據在內存中的臨時容器,它包含了庫表數據在內存中的臨時拷貝,位於資料庫與應用程序之間,其作用是為了降低應用程序對物理數據源訪問的頻次,從而提高應用的運行性能。
Hibernate的緩存機制
1.1持久化層的緩存的范圍
持久層設計中,往往需要考慮幾個不同層次中的數據緩存策略。這些層次的劃分標准針對不同情況有所差異,一般而言,ORM的數據緩存應包含如下幾個層次:
事務級緩存(Transaction Layer Cache)
緩存只能被當前事務訪問。緩存的生命周期依賴於事務的生命周期,當事務結束時,緩存也就結束生命周期。在此范圍下,緩存的介質是內存。事務可以是資料庫事務或者應用事務,每個事務都有獨自的緩存,緩存內的數據通常採用相互關聯的對象形式。
應用級/進程級緩存(Application/Process Layer Cache)
緩存被進程內的所有事務共享。這些事務有可能是並發訪問緩存,因此必須對緩存採取必要的事務隔離機制。緩存的生命周期依賴於進程的生命周期,進程結束時,緩存也就結束了生命周期。進程范圍的緩存可能會存放大量的數據,所以存放的介質可以是內存或硬碟。緩存內的數據既可以是相互關聯的對象形式也可以是對象的鬆散數據形式。對象的鬆散數據形式有點類似於對象的序列化數據,但是對象分解為鬆散的演算法比對象序列化的演算法要求更快。
集群級緩存(Cluster Layer Cache)
在集群環境中,緩存被一個機器或者多個機器的進程共享。緩存中的數據被復制到集群環境中的每個進程節點,進程間通過遠程通信來保證緩存中的數據的一致性,緩存中的數據通常採用對象的鬆散數據形式。對大多數應用來說,應該慎重地考慮是否需要使用集群范圍的緩存,因為訪問的速度不一定會比直接訪問資料庫數據的速度快多少。
持久層提供以上多種層次的緩存。如果在事務級緩存中沒有查到相應的數據,還可以到進程級或集群級緩存內查詢,如果還是沒有查到,那麼只有到資料庫中查詢。事務級緩存是持久化層的第一級緩存,通常它是必需的;進程級或集群級緩存是持久化層的第二級緩存,通常是可選的。
1.2 hibernate緩存機制
Hibernate提供了兩種緩存,第一種是Session的緩存,又稱為一級緩存。由於Session對象的生命周期通常對應一個資料庫事務或者一個應用事務,因此它的緩存是事務范圍的緩存。第一級緩存是必需的,不允許而且事實上也無法卸除。在第一級緩存中,持久化類的每個實例都具有唯一的OID。
㈢ hibernate 是否 一定 用 緩存
hibernate的緩存有一級緩存、二級緩存和查詢緩存。其中一級緩存是必需的,它緩存在會話期間的entity。二級緩存和查詢緩存是可選的。
㈣ 什麼是hibernate緩存機制
這是面試中經常問到的一個問題,樓主可以按照我的思路回答,准你回答得很完美,首先說下Hibernate緩存的作用(即為什麼要用緩存機制),然後再具體說說Hibernate中緩存的分類情況,
最後可以舉個具體的例子。
Hibernate緩存的作用:
Hibernate是一個持久層框架,經常訪問物理資料庫,為了降低應用程序對物理數據源訪問的頻次,從而提高應用程序的運行性能。緩存內的數據是對物理數據源中的數據的復制,應用程序在運行時從緩存讀寫數據,在特定的時刻或事件會同步緩存和物理數據源的數據
Hibernate緩存分類:
Hibernate緩存包括兩大類:Hibernate一級緩存和Hibernate二級緩存
Hibernate一級緩存又稱為「Session的緩存」,它是內置的,不能被卸載(不能被卸載的意思就是這種緩存不具有可選性,必須有的功能,不可以取消session緩存)。由於Session對象的生命周期通常對應一個資料庫事務或者一個應用事務,因此它的緩存是事務范圍的緩存。第一級緩存是必需的,不允許而且事實上也無法卸除。在第一級緩存中,持久化類的每個實例都具有唯一的OID。
Hibernate二級緩存又稱為「SessionFactory的緩存」,由於SessionFactory對象的生命周期和應用程序的整個過程對應,因此Hibernate二級緩存是進程范圍或者集群范圍的緩存,有可能出現並發問題,因此需要採用適當的並發訪問策略,該策略為被緩存的數據提供了事務隔離級別。第二級緩存是可選的,是一個可配置的插件,在默認情況下,SessionFactory不會啟用這個插件。
什麼樣的數據適合存放到第二級緩存中?
1 很少被修改的數據
2 不是很重要的數據,允許出現偶爾並發的數據
3 不會被並發訪問的數據
4 常量數據
不適合存放到第二級緩存的數據?
1經常被修改的數據
2 .絕對不允許出現並發訪問的數據,如財務數據,絕對不允許出現並發
3 與其他應用共享的數據。
Hibernate查找對象如何應用緩存?
當Hibernate根據ID訪問數據對象的時候,首先從Session一級緩存中查;查不到,如果配置了二級緩存,那麼從二級緩存中查;如果都查不到,再查詢資料庫,把結果按照ID放入到緩存
刪除、更新、增加數據的時候,同時更新緩存
Hibernate管理緩存實例
無論何時,我們在管理Hibernate緩存(Managing the caches)時,當你給save()、update()或saveOrUpdate()方法傳遞一個對象時,或使用load()、 get()、list()、iterate() 或scroll()方法獲得一個對象時, 該對象都將被加入到Session的內部緩存中。
當隨後flush()方法被調用時,對象的狀態會和資料庫取得同步。 如果你不希望此同步操作發生,或者你正處理大量對象、需要對有效管理內存時,你可以調用evict() 方法,從一級緩存中去掉這些對象及其集合。
這樣從頭到尾一說的話,很全很詳細,估計面試官對你的印象很好。不過也不要面面俱到,樓主可以挑一些自己懂得的內容說,不是很懂的內容可以省略,免得出漏子。
㈤ hibernate的緩存是什麼,一級緩存和二級緩存分別是什麼,有什麼區別
hibernate緩存機制就是 已一種數據結構(hashmam)將你查詢過的數據保存在內存中
當你下次再次查詢的時候 hibernate首先會先到內存中的對應map中查看是否存在你要查找的值
如果有 直接取出來給你,沒有再發sql 這些都是通過代理實現的
一級緩存 和二級緩存 本質區別就是 hibernate銷毀內存中數據時間不同
2級緩存也稱為session級別的緩存 數據和session同周期 當前session沒有了緩存也沒有了
1級緩存也稱為factory級別的 時期較2級緩存長
理解了,望採納!
㈥ Hibernate 二級緩存的作用
true
org.hibernate.cache.ehcacheprovider
前一句是打開二級緩存,後一句是啟用第三方緩存產品(可改變,上面eache是hibernate官方默認的第三方緩存產品)
緩存是否實用,要看你的需求,
如果你的系統,瀏覽的人數比較多,但是增刪的比較少,緩存的功勞非常大
如果你的系統即時性非常強,那麼緩存的命中率就比較低,同時更新數據時,hibernate需要額外提供資源維護緩存與數據的一致
㈦ 什麼是hibernate的二級緩存
在向大家詳細介紹Hibernate二級緩存之前,首先讓大家了解下一級緩存,然後全面介紹Hibernate二級緩存。
Hibernate中提供了兩級Cache,第一級別的緩存是Session級別的緩存,它是屬於事務范圍的緩存。這一級別的緩存由hibernate管理的,一般情況下無需進行干預;第二級別的緩存是SessionFactory級別的緩存,它是屬於進程范圍或群集范圍的緩存。這一級別的緩存可以進行配置和更改,並且可以動態載入和卸載。 Hibernate還為查詢結果提供了一個查詢緩存,它依賴於第二級緩存。
一. 一級緩存和二級緩存的比較:
第一級緩存 第二級緩存 存放數據的形式相互關聯的持久化對象 對象的散裝數據 緩存的范圍事務范圍,每個事務都有單獨的第一級緩存進程范圍或集群范圍,緩存被同一個進程或集群范圍內的所有事務共享並發訪問策略由於每個事務都擁有單獨的第一級緩存,不會出現並發問題,無需提供並發訪問策略由於多個事務會同時訪問第二級緩存中相同數據,因此必須提供適當的並發訪問策略,來保證特定的事務隔離級別數據過期策略沒有提供數據過期策略。處於一級緩存中的對象永遠不會過期,除非應用程序顯式清空緩存或者清除特定的對象必須提供數據過期策略,如基於內存的緩存中的對象的最大數目,允許對象處於緩存中的最長時間,以及允許對象處於緩存中的最長空閑時間物理存儲介質內存內存和硬碟。對象的散裝數據首先存放在基於內存的緩存中,當內存中對象的數目達到數據過期策略中指定上限時,就會把其餘的對象寫入基於硬碟的緩存中。緩存的軟體實現在Hibernate的Session的實現中包含了緩存的實現由第三方提供,Hibernate僅提供了緩存適配器(CacheProvider)。用於把特定的緩存插件集成到Hibernate中。啟用緩存的方式只要應用程序通過Session介面來執行保存、更新、刪除、載入和查詢資料庫數據的操作,Hibernate就會啟用第一級緩存,把資料庫中的數據以對象的形式拷貝到緩存中,對於批量更新和批量刪除操作,如果不希望啟用第一級緩存,可以繞過Hibernate API,直接通過JDBC API來執行指操作。用戶可以在單個類或類的單個集合的粒度上配置第二級緩存。如果類的實例被經常讀但很少被修改,就可以考慮使用第二級緩存。只有為某個類或集合配置了第二級緩存,Hibernate在運行時才會把它的實例加入到第二級緩存中。用戶管理緩存的方式第一級緩存的物理介質為內存,由於內存容量有限,必須通過恰當的檢索策略和檢索方式來限制載入對象的數目。Session的 evit()方法可以顯式清空緩存中特定對象,但這種方法不值得推薦。第二級緩存的物理介質可以是內存和硬碟,因此第二級緩存可以存放大量的數據,數據過期策略的maxElementsInMemory屬性值可以控制內存中的對象數目。管理第二級緩存主要包括兩個方面:選擇需要使用第二級緩存的持久類,設置合適的並發訪問策略:選擇緩存適配器,設置合適的數據過期策略。
二. 一級緩存的管理:
當應用程序調用Session的save()、update()、savaeOrUpdate()、get()或load(),以及調用查詢介面的 list()、iterate()或filter()方法時,如果在Session緩存中還不存在相應的對象,Hibernate就會把該對象加入到第一級緩存中。當清理緩存時,Hibernate會根據緩存中對象的狀態變化來同步更新資料庫。 Session為應用程序提供了兩個管理緩存的方法: evict(Object obj):從緩存中清除參數指定的持久化對象。 clear():清空緩存中所有持久化對象。
三. Hibernate二級緩存的管理:
1. Hibernate二級緩存策略的一般過程如下:
1) 條件查詢的時候,總是發出一條select * from table_name where …. (選擇所有欄位)這樣的SQL語句查詢資料庫,一次獲得所有的數據對象。
2) 把獲得的所有數據對象根據ID放入到第二級緩存中。
3) 當Hibernate根據ID訪問數據對象的時候,首先從Session一級緩存中查;查不到,如果配置了二級緩存,那麼從二級緩存中查;查不到,再查詢資料庫,把結果按照ID放入到緩存。
4) 刪除、更新、增加數據的時候,同時更新緩存。
Hibernate二級緩存策略,是針對於ID查詢的緩存策略,對於條件查詢則毫無作用。為此,Hibernate提供了針對條件查詢的Query Cache。
2. 什麼樣的數據適合存放到第二級緩存中?
1) 很少被修改的數據
2) 不是很重要的數據,允許出現偶爾並發的數據
3) 不會被並發訪問的數據
4) 參考數據,指的是供應用參考的常量數據,它的實例數目有限,它的實例會被許多其他類的實例引用,實例極少或者從來不會被修改。
3. 不適合存放到第二級緩存的數據?
1) 經常被修改的數據
2) 財務數據,絕對不允許出現並發
3) 與其他應用共享的數據。
4. 常用的緩存插件 Hibernater二級緩存是一個插件,下面是幾種常用的緩存插件:
◆EhCache:可作為進程范圍的緩存,存放數據的物理介質可以是內存或硬碟,對Hibernate的查詢緩存提供了支持。
◆OSCache:可作為進程范圍的緩存,存放數據的物理介質可以是內存或硬碟,提供了豐富的緩存數據過期策略,對Hibernate的查詢緩存提供了支持。
◆SwarmCache:可作為群集范圍內的緩存,但不支持Hibernate的查詢緩存。
◆JBossCache:可作為群集范圍內的緩存,支持事務型並發訪問策略,對Hibernate的查詢緩存提供了支持。
5. 配置Hibernate二級緩存的主要步驟:
1) 選擇需要使用二級緩存的持久化類,設置它的命名緩存的並發訪問策略。這是最值得認真考慮的步驟。
2) 選擇合適的緩存插件,然後編輯該插件的配置文件。
㈧ hibernate工作原理及為什麼要用
hibernate 簡介:
hibernate是一個開源框架,它是對象關聯關系映射的框架,它對JDBC做了輕量級的封裝,而我們java程序員可以使用面向對象的思想來操縱資料庫。
hibernate核心介面
session:負責被持久化對象CRUD操作
sessionFactory:負責初始化hibernate,創建session對象
configuration:負責配置並啟動hibernate,創建SessionFactory
Transaction:負責事物相關的操作
Query和Criteria介面:負責執行各種資料庫查詢
hibernate工作原理:
1.通過Configuration config = new Configuration().configure();//讀取並解析hibernate.cfg.xml配置文件
2.由hibernate.cfg.xml中的<mapping resource="com/xx/User.hbm.xml"/>讀取並解析映射信息
3.通過SessionFactory sf = config.buildSessionFactory();//創建SessionFactory
4.Session session = sf.openSession();//打開Sesssion
5.Transaction tx = session.beginTransaction();//創建並啟動事務Transation
6.persistent operate操作數據,持久化操作
7.tx.commit();//提交事務
8.關閉Session
9.關閉SesstionFactory
為什麼要用hibernate:
1. 對JDBC訪問資料庫的代碼做了封裝,大大簡化了數據訪問層繁瑣的重復性代碼。
2. Hibernate是一個基於JDBC的主流持久化框架,是一個優秀的ORM實現。他很大程度的簡化DAO層的編碼工作
3. hibernate使用Java反射機制,而不是位元組碼增強程序來實現透明性。
4. hibernate的性能非常好,因為它是個輕量級框架。映射的靈活性很出色。它支持各種關系資料庫,從一對一到多對多的各種復雜關系。
Hibernate是如何延遲載入?get與load的區別
1. 對於Hibernate get方法,Hibernate會確認一下該id對應的數據是否存在,首先在session緩存中查找,然後在二級緩存中查找,還沒有就查詢資料庫,數據 庫中沒有就返回null。這個相對比較簡單,也沒有太大的爭議。主要要說明的一點就是在這個版本(bibernate3.2以上)中get方法也會查找二級緩存!
2. Hibernate load方法載入實體對象的時候,根據映射文件上類級別的lazy屬性的配置(默認為true),分情況討論:
(1)若為true,則首先在Session緩存中查找,看看該id對應的對象是否存在,不存在則使用延遲載入,返回實體的代理類對象(該代理類為實體類的子類,由CGLIB動態生成)。等到具體使用該對象(除獲取OID以外)的時候,再查詢二級緩存和資料庫,若仍沒發現符合條件的記錄,則會拋出一個ObjectNotFoundException。
(2)若為false,就跟Hibernateget方法查找順序一樣,只是最終若沒發現符合條件的記錄,則會拋出一個ObjectNotFoundException。
這里get和load有兩個重要區別:
如果未能發現符合條件的記錄,Hibernate get方法返回null,而load方法會拋出一個ObjectNotFoundException。
load方法可返回沒有載入實體數據的代 理類實例,而get方法永遠返回有實體數據的對象。
(對於load和get方法返回類型:好多書中都說:「get方法永遠只返回實體類」,實際上並不正 確,get方法如果在session緩存中找到了該id對應的對象,如果剛好該對象前面是被代理過的,如被load方法使用過,或者被其他關聯對象延遲加 載過,那麼返回的還是原先的代理對象,而不是實體類對象,如果該代理對象還沒有載入實體數據(就是id以外的其他屬性數據),那麼它會查詢二級緩存或者數 據庫來載入數據,但是返回的還是代理對象,只不過已經載入了實體數據。)
總之對於get和load的根本區別,一句話,hibernate對於 load方法認為該數據在資料庫中一定存在,可以放心的使用代理來延遲載入,如果在使用過程中發現了問題,只能拋異常;而對於get方 法,hibernate一定要獲取到真實的數據,否則返回null。
Hibernate中怎樣實現類之間的關系?(如:一對多、多對多的關系)
類與類之間的關系主要體現在表與表之間的關系進行操作,它們都市對對象進行操作,我們程序中把所有的表與類都映射在一起,它們通過配置文件中的many-to-one、one-to-many、many-to-many、
說下Hibernate的緩存機制:
Hibernate緩存的作用:
Hibernate是一個持久層框架,經常訪問物理資料庫,為了降低應用程序對物理數據源訪問的頻次,從而提高應用程序的運行性能。緩存內的數據是對物理數據源中的數據的復制,應用程序在運行時從緩存讀寫數據,在特定的時刻或事件會同步緩存和物理數據源的數據
Hibernate緩存分類:
Hibernate緩存包括兩大類:Hibernate一級緩存和Hibernate二級緩存
Hibernate一級緩存又稱為「Session的緩存」,它是內置的,意思就是說,只要你使用hibernate就必須使用session緩存。由於Session對象的生命周期通常對應一個資料庫事務或者一個應用事務,因此它的緩存是事務范圍的緩存。在第一級緩存中,持久化類的每個實例都具有唯一的OID。
Hibernate二級緩存又稱為「SessionFactory的緩存」,由於SessionFactory對象的生命周期和應用程序的整個過程對應,因此Hibernate二級緩存是進程范圍或者集群范圍的緩存,有可能出現並發問題,因此需要採用適當的並發訪問策略,該策略為被緩存的數據提供了事務隔離級別。第二級緩存是可選的,是一個可配置的插件,在默認情況下,SessionFactory不會啟用這個插件。
什麼樣的數據適合存放到第二級緩存中?
1 很少被修改的數據
2 不是很重要的數據,允許出現偶爾並發的數據
3 不會被並發訪問的數據
4 常量數據
不適合存放到第二級緩存的數據?
1經常被修改的數據
2 .絕對不允許出現並發訪問的數據,如財務數據,絕對不允許出現並發
3 與其他應用共享的數據。
Hibernate查找對象如何應用緩存?
當Hibernate根據ID訪問數據對象的時候,首先從Session一級緩存中查;查不到,如果配置了二級緩存,那麼從二級緩存中查;如果都查不到,再查詢資料庫,把結果按照ID放入到緩存
刪除、更新、增加數據的時候,同時更新緩存
Hibernate管理緩存實例
無論何時,我們在管理Hibernate緩存(Managing the caches)時,當你給save()、update()或saveOrUpdate()方法傳遞一個對象時,或使用load()、 get()、list()、iterate() 或scroll()方法獲得一個對象時, 該對象都將被加入到Session的內部緩存中。
當隨後flush()方法被調用時,對象的狀態會和資料庫取得同步。 如果你不希望此同步操作發生,或者你正處理大量對象、需要對有效管理內存時,你可以調用evict() 方法,從一級緩存中去掉這些對象及其集合。
Hibernate的查詢方式
Sql、Criteria,object comptosition
Hql:
1、 屬性查詢
2、 參數查詢、命名參數查詢
3、 關聯查詢
4、 分頁查詢
5、 統計函數
如何優化Hibernate?
1.使用雙向一對多關聯,不使用單向一對多
2.靈活使用單向一對多關聯
3.不用一對一,用多對一取代
4.配置對象緩存,不使用集合緩存
5.一對多集合使用Bag,多對多集合使用Set
6. 繼承類使用顯式多態
7. 表欄位要少,表關聯不要怕多,有二級緩存撐腰
hibernate的開發步驟:
開發步驟
1)搭建好環境
引入hibernate最小的jar包
准備Hibernate.cfg.xml啟動配置文件
2)寫實體類(pojo)
3)為實體類寫映射文件"User.hbm.xml"
在hibernate.cfg.xml添加映射的實體
4)創建庫表
5)寫測試類
獲得Configuration
創建SessionFactory
打開Session
開啟事務
使用session操作數據
提交事務
關閉資源
㈨ Hibernate緩存何時使用和如何使用
關於hibernate緩存的問題基本的緩存原理
Hibernate緩存分為二級
第一級存放於session中稱為一級緩存 默認帶有且不能卸載
第二級是由sessionFactory控制的進程級緩存 是全局共享的緩存 凡是會調用二級緩存的查詢方法 都會從中受益 只有經正確的配置後二級緩存才會發揮作用 同時在進行條件查詢時必須使用相應的方法才能從緩存中獲取數據 比如erate()方法 load get方法等 必須注意的是session find方法永遠是從資料庫中獲取數據 不會從二級緩存中獲取數據 即便其中有其所需要的數據也是如此
查詢時使用緩存的實現過程為 首先查詢一級緩存中是否具有需要的數據 如果沒有 查詢二級緩存 如果二級緩存中也沒有 此時再執行查詢資料庫的工作 要注意的是 此 種方式的查詢速度是依次降低的
存在的問題
一級緩存的問題以及使用二級緩存的原因
因為Session的生命期往往很短 存在於Session內部的第一級最快緩存的生命期當然也很短 所以第一級緩存的命中率是很低的 其對系統性能的改善也是很有限的 當然 這個Session內部緩存的主要作用是保持Session內部數據狀態同步 並非是hibernate為了大幅提高系統性能所提供的
為了提高使用hibernate的性能 除了常規的一些需要注意的方法比如
使用延遲載入 迫切外連接 查詢過濾等以外 還需要配置hibernate的二級緩存 其對系統整體性能的改善往往具有立竿見影的效果!
(經過自己以前作項目的經驗 一般會有 ~ 倍的性能提高)
N+ 次查詢的問題
什麼時候會遇到 +N的問題?
前提 Hibernate默認表與表的關聯方法是fetch= select 不是fetch= join 這都是為了懶載入而准備的
)一對多(<set><list>) 在 的這方 通過 條sql查找得到了 個對象 由於關聯的存在 那麼又需要將這個對象關聯的集合取出 所以合集數量是n還要發出n條sql 於是本來的 條sql查詢變成了 +n條
)多對一<many to one> 在多的這方 通過 條sql查詢得到了n個對象 由於關聯的存在 也會將這n個對象對應的 方的對象取出 於是本來的 條sql查詢變成了 +n條
)iterator 查詢時 一定先去緩存中找( 條sql查集合 只查出ID) 在沒命中時 會再按ID到庫中逐一查找 產生 +n條SQL
怎麼解決 +N 問題?
)lazy=true hibernate 開始已經默認是lazy=true了 lazy=true時不會立刻查詢關聯對象 只有當需要關聯對象(訪問其屬性 非id欄位)時才會發生查詢動作
)使用二級緩存 二級緩存的應用將不怕 +N 問題 因為即使第一次查詢很慢(未命中) 以後查詢直接緩存命中也是很快的 剛好又利用了 +N
) 當然你也可以設定fetch= join 一次關聯表全查出來 但失去了懶載入的特性
執行條件查詢時 iterate()方法具有著名的 n+ 次查詢的問題 也就是說在第一次查詢時iterate方法會執行滿足條件的查詢結果數再加一次(n+ )的查詢 但是此問題只存在於第一次查詢時 在後面執行相同查詢時性能會得到極大的改善 此方法適合於查詢數據量較大的業務數據
但是注意 當數據量特別大時(比如流水線數據等)需要針對此持久化對象配置其具體的緩存策略 比如設置其存在於緩存中的最大記錄數 緩存存在的時間等參數 以避免系統將大量的數據同時裝載入內存中引起內存資源的迅速耗盡 反而降低系統的性能!!!
使用hibernate二級緩存的其他注意事項
關於數據的有效性
另外 hibernate會自行維護二級緩存中的數據 以保證緩存中的數據和資料庫中的真實數據的一致性!無論何時 當你調用save() update()或 saveOrUpdate()方法傳遞一個對象時 或使用load() get() list() iterate() 或scroll()方法獲得一個對象時 該對象都將被加入到Session的內部緩存中 當隨後flush()方法被調用時 對象的狀態會和資料庫取得同步
也就是說刪除 更新 增加數據的時候 同時更新緩存 當然這也包括二級緩存!
只要是調用hibernate API執行資料庫相關的工作 hibernate都會為你自動保證 緩存數據的有效性!!
但是 如果你使用了JDBC繞過hibernate直接執行對資料庫的操作 此時 Hibernate不會/也不可能自行感知到資料庫被進行的變化改動 也就不能再保證緩存中數據的有效性!!
這也是所有的ORM產品共同具有的問題 幸運的是 Hibernate為我們暴露了Cache的清除方法 這給我們提供了一個手動保證數據有效性的機會!!
一級緩存 二級緩存都有相應的清除方法
其中二級緩存提供的清除方法為
按對象class清空緩存
按對象class和對象的主鍵id清空緩存
清空對象的集合中的緩存數據等
適合使用的情況
並非所有的情況都適合於使用二級緩存 需要根據具體情況來決定 同時可以針對某一個持久化對象配置其具體的緩存策略
適合於使用二級緩存的情況
數據不會被第三方修改
一般情況下 會被hibernate以外修改的數據最好不要配置二級緩存 以免引起不一致的數據 但是如果此數據因為性能的原因需要被緩存 同時又有可能被第 方比如SQL修改 也可以為其配置二級緩存 只是此時需要在sql執行修改後手動調用cache的清除方法 以保證數據的一致性
數據大小在可接收范圍之內
如果數據表數據量特別巨大 此時不適合於二級緩存 原因是緩存的數據量過大可能會引起內存資源緊張 反而降低性能 如果數據表數據量特別巨大 但是經常使用的往往只是較新的那部分數據 此時 也可為其配置二級緩存 但是必須單獨配置其持久化類的緩存策略 比如最大緩存數 緩存過期時間等 將這些參數降低至一個合理的范圍(太高會引起內存資源緊張 太低了緩存的意義不大)
數據更新頻率低
對於數據更新頻率過高的數據 頻繁同步緩存中數據的代價可能和 查詢緩存中的數據從中獲得的好處相當 壞處益處相抵消 此時緩存的意義也不大
非關鍵數據(不是財務數據等)
財務數據等是非常重要的數據 絕對不允許出現或使用無效的數據 所以此時為了安全起見最好不要使用二級緩存
因為此時 正確性 的重要性遠遠大於 高性能 的重要性
目前系統中使用hibernate緩存的建議
目前情況
一般系統中有三種情況會繞開hibernate執行資料庫操作
多個應用系統同時訪問一個資料庫
此種情況使用hibernate二級緩存會不可避免的造成數據不一致的問題 此時要進行詳細的設計 比如在設計上避免對同一數據表的同時的寫入操作 使用資料庫各種級別的鎖定機制等
動態表相關
所謂 動態表 是指在系統運行時根據用戶的操作系統自動建立的數據表
比如 自定義表單 等屬於用戶自定義擴展開發性質的功能模塊 因為此時數據表是運行時建立的 所以不能進行hibernate的映射 因此對它的操作只能是繞開hibernate的直接資料庫JDBC操作
如果此時動態表中的數據沒有設計緩存 就不存在數據不一致的問題
如果此時自行設計了緩存機制 則調用自己的緩存同步方法即可
使用sql對hibernate持久化對象表進行批量刪除時
此時執行批量刪除後 緩存中會存在已被刪除的數據
分析
當執行了第 條(sql批量刪除)後 後續的查詢只可能是以下三種方式
a session find()方法
根據前面的總結 find方法不會查詢二級緩存的數據 而是直接查詢資料庫
所以不存在數據有效性的問題
b 調用iterate方法執行條件查詢時
根據iterate查詢方法的執行方式 其每次都會到資料庫中查詢滿足條件的id值 然後再根據此id 到緩存中獲取數據 當緩存中沒有此id的數據才會執行資料庫查詢
如果此記錄已被sql直接刪除 則iterate在執行id查詢時不會將此id查詢出來 所以 即便緩存中有此條記錄也不會被客戶獲得 也就不存在不一致的情況 (此情況經過測試驗證)
c 用get或load方法按id執行查詢
客觀上此時會查詢得到已過期的數據 但是又因為系統中執行sql批量刪除一般是針對中間關聯數據表 對於中間關聯表的查詢一般都是採用條件查詢 按id來查詢某一條關聯關系的幾率很低 所以此問題也不存在!
如果某個值對象確實需要按id查詢一條關聯關系 同時又因為數據量大使用 了sql執行批量刪除 當滿足此兩個條件時 為了保證按id 的查詢得到正確的結果 可以使用手動清楚二級緩存中此對象的數據的方法!!(此種情況出現的可能性較小)
建 議
建議不要使用sql直接執行數據持久化對象的數據的更新 但是可以執行 批量刪除 (系統中需要批量更新的地方也較少)
如果必須使用sql執行數據的更新 必須清空此對象的緩存數據 調用
SessionFactory evict(class)
SessionFactory evict(class id)等方法
在批量刪除數據量不大的時候可以直接採用hibernate的批量刪除 這樣就不存在繞開hibernate執行sql產生的緩存數據一致性的問題
不推薦採用hibernate的批量刪除方法來刪除大批量的記錄數據
原因是hibernate的批量刪除會執行 條查詢語句外加 滿足條件的n條刪除語句 而不是一次執行一條條件刪除語句!!當待刪除的數據很多時會有很大的性能瓶頸!!!如果批量刪除數據量較大 比如超過 條 可以採用JDBC直接刪除 這樣作的好處是只執行一條sql刪除語句 性能會有很大的改善 同時 緩存數據同步的問題 可以採用 hibernate清除二級緩存中的相關數據的方法
調 用
SessionFactory evict(class) ;
SessionFactory evict(class id)等方法
所以說 對於一般的應用系統開發而言(不涉及到集群 分布式數據同步問題等) 因為只在中間關聯表執行批量刪除時調用了sql執行 同時中間關聯表一般是執行條件查詢不太可能執行按id查詢 所以 此時可以直接執行sql刪除 甚至不需要調用緩存的清除方法 這樣做不會導致以後配置了二級緩存引起數據有效性的問題
退一步說 即使以後真的調用了按id查詢中間表對象的方法 也可以通過調用清除緩存的方法來解決
具體的配置方法
根據我了解的很多hibernate的使用者在調用其相應方法時都迷信的相信 hibernate會自行為我們處理性能的問題 或者 hibernate 會自動為我們的所有操作調用緩存 實際的情況是hibernate雖然為我們提供了很好的緩存機制和擴展緩存框架的支持 但是必須經過正確的調用其才有可能發揮作用!!所以造成很多使用hibernate的系統的性能問題 實際上並不是hibernate不行或者不好 而是因為使用者沒有正確的了解其使用方法造成的 相反 如果配置得當hibernate的性能表現會讓你有相當 驚喜的 發現 下面我講解具體的配置方法
ibernate提供了二級緩存的介面
net sf hibernate cache Provider
同時提供了一個默認的 實現net sf hibernate cache HashtableCacheProvider
也可以配置 其他的實現 比如ehcache jbosscache等
具體的配置位置位於hibernate cfg xml文件中
- <propertyname= hibernate cache use_query_cache >true</property><propertyname= hibernate cache provider_class >net sf hibernate cache HashtableCacheProvider</property>
很多的hibernate使用者在 配置到 這一步 就以為 完事了
注意 其實光這樣配 根本就沒有使用hibernate的二級緩存 同時因為他們在使用hibernate時大多時候是馬上關閉session 所以 一級緩存也沒有起到任何作用 結果就是沒有使用任何緩存 所有的hibernate操作都是直接操作的資料庫!!性能可以想見
正確的辦法是除了以上的配置外還應該配置每一個vo對象的具體緩存策略 在影射文件中配置 例如
- <hibernate mapping><classname= sobey *** m model entitySystem vo DataTypeVO table= dcm_datatype ><cacheusage= read write /><idname= id column= TYPEID type= java lang Long ><generatorclass= sequence /></id><propertyname= name column= NAME type= java lang String /><propertyname= dbType column= DBTYPE type= java lang String /></class></hibernate mapping>
關鍵就是這個<cache usage= read write /> 其有幾個選擇read only read write transactional 等
然後在執行查詢時 注意了 如果是條件查詢 或者返回所有結果的查詢 此時session find()方法 不會獲取緩存中的數據 只有調用erate()方法時才會調緩存的數據
同時 get 和 load方法 是都會查詢緩存中的數據
對於不同的緩存框架具體的配置方法會有不同 但是大體是以上的配置(另外 對於支持事務型 以及支持集群的環境的配置我會爭取在後續的文章中中 發表出來)
