1、Hibernate的數據檢索策略是面向對象的策略,對與不一樣的檢索狀況,應使用不一樣的策略,以提升效率節省資源。常用的是當即檢索和延遲檢索,預先抓取和批量檢索都是爲了優化加載性能而設計的策略。檢索通常是創建在表關聯的基礎上的因此咱們先創建三張表Team與Student是一對多關係,Student和Certificate是一對一關係。
Team→id:String、teamName:String
Student→id:String、team_id、name、cardid、age
Certificate→id:String、describe
在這裏Team至關於原對象Student至關於Team的附屬物,Certificate至關於Student的附屬物。當加載一個原對象時,原對象對附屬物的使用有2中狀況:(1)立刻就用附屬物的數據(2)可能一會用,可能不用。第一種狀況適用於當即檢索,第二種狀況適用於延遲檢索。
1.當即檢索
當即檢索的配置文件標識符爲lazy="false"。算法
通常狀況下咱們把一對一和多對一這樣後者爲一的對象用於當即檢索,由於是「一」的這段,所帶來的性能消耗也有限。當即裝載附屬物有個好處,原對象脫離管理成爲VO之後,仍然可使用這些附屬物。而對一對多和多對多關聯對象則不適合當即檢索。好比班級和學生是一對多的關係,當取得班級對象時,如過是當即檢索,就會把班級的全部學生對象組裝起來,這種資源消耗在這沒有必要。
2.延遲檢索
延遲檢索的配置文件標識符爲lazy="true"。
延遲檢索就是等到須要用到時(好比調用了Team.getTeamName()。調用stu.getTeam()不行,必須以Team爲主體取得附屬物時,纔會實現延遲加載)纔會去取被關聯對象Team。所以若是在Student對象的配置文件中設置了對Team進行延遲檢索,則在取的學生1對象時,Hibernate僅把學生1對象設置爲當即檢索的對象和屬性裝配進學生1對象,而並不會當即去組裝設爲延遲檢索的附屬物,只有在同一個Session中使用到班級1時,Hibernate纔會從數據庫中查找數據並裝配成班級1對象。
若是把班級對象歸入另外一個Session中,使用org.hibernate.Hibernate這個類的initialize()方法,這時脫離Session管理仍然能夠從班級對象中取出數據。
3.預先抓取
預先抓取的配置文件標識符爲fetch="join"
若是把三個表之間的關係都設爲當即檢索,取得班級對象時,從而遞歸的獲得學生和身份證對象。若是有100個學生,則要發送100條SQL語句去取100個身份證。這樣會很大程度的下降性能。因此必須減小發送的SQL語句的數量。使用預先抓取只是用一條SQL語句就能代替當即檢索的100條SQL語句。再具體點好比有一堆貨物,原先有100我的排隊順序去背,如今讓一我的一次揹回來,反而影響性能。每次背的數量可用hibernate.max_fetch_depth來控制。還有一點須要注意,HQL使用外鏈接查詢時忽略配置文件中配置的預先抓取策略,如:Query q = session .createQuery("from Strudent as s left join s.team");因此咱們應該改成Query q = session .createQuery("from Strudent as s left join fetch s.team");
僅從使用角度來講。預先抓取和當即檢索的效果同樣,只不過預先抓取能減小SQL語句的條數。
4.批量加載
批量加載老是和當即或延遲加載聯繫在一塊兒,分爲批量當即加載和批量延遲加載。主要是控制發送SQL語句的條數,較少資源的消耗。
對於一對多、多對多在集合的配置中設置,以set爲例:
<set name = "students" inverse="true" batch-size="3">
<key column="team_id"/>
<one-to-many class="model.Student"/>
</set>
一對1、多對一好比學生對班級是多對一關係,要實現對班級的批量加載,以下:
<class name="model.Team" table="team" batch-size="3">
2、下面分析一下.hbm.xml文件
有3個實體,Team、Student、Certificate,Team與Student是一對多關係,Student和Certificate是一對一。
(1).Student.hbm.xml配置文件源碼:數據庫
Student.hbm.xml配置文件信息的解釋以下:
第5行:model.Student類對應的數據庫表是student表。lazy="true"當使用一對1、多對一方式加載Student類時,將採用延遲加載(前提是設置預先抓取爲false)。
第六、七、8行:Student類有一個主鍵id,id由Hibernate自動生成,生成算法是uuid.hex。在內存中有不少對象,能夠經過unsaved-value="null"來判斷對象是持久化的仍是臨時狀態。當對象的id值爲unsaved-value指定的"null"時,認爲未持久化,不然認爲此對象是持久化或託管狀態。注意int、long型的主鍵id的默認unsaved-value="0"。
第12行:一個一對一關聯的對象屬性,名爲cer,fetch="join"在獲得Student對象時。採用預先抓取獲得cer對象。cascade="all"表示級聯爲all,說明Student的crud操做都會影響cer對象。
第13行:一個多對一關聯的對象屬性,名爲Team,在Student表中經過team_id與Team對象發生關聯,引用team中id成外鍵,沒個Student對象對應惟一的team。team的實體類是model.Team。在取得Student實例時。使用預先抓取獲得team對象。
(2).Certificate.hbm.xml配置文件源碼:緩存
Certificate.hbm.xml配置文件信息的解釋以下:
第六、七、八、九、10行:Certificate和Student是一對一關聯,使用的是以主鍵關聯,即Certificate和Student公用一個主鍵值。Certificate的主鍵id生成使用外鍵方式(generator class="foreign"),此外鍵參考一對一引用中的"stu"變量。
第11行:一對一關聯model.Student類,當取Certificate對象時,預先抓取Student類(fetch="join"),聲明瞭constrained="true"。這個選項影響save()和delete()在級聯執行的前後順序以及決定該關聯類可否被延遲加載(true時,此是的Student類纔可被延遲加載)。
(3).Team.hbm.xml配置文件源碼:session
Team.hbm.xml配置文件信息的解釋以下:
第十一、十二、1三、14行:一個Set集合名爲students,採用延遲加載,在實體對象Student對象的student表中。一team_id列對應Team對象。
(4)須要在說一下的問題:
cascade屬性的用法:
save-update:在執行save/update/saveOrUpdate時進行關聯操做。
delete:在執行delete時進行關聯操做。
none:全部狀況下均不進行關聯操做。這是默認值。
all的意思是save-update + delete 。
all-delete-orphan 的意思是當對象圖中產生孤兒節點時,在數據庫中刪除該節點 。
舉個例子說一下all-delete-orphan,Category與Item是一對多的關係,也就是說Category類中有個Set類型的變量items.
舉個例子,現items中存兩個Item, item1,item2,若是定義關係爲all-delete-orphan ,當items中刪除掉一個item(好比用remove()方法刪除item1),那麼被刪除的Item類實例 ,將變成孤兒節點,當執行category.update(),或session.flush()時
hibernate同步緩存和數據庫,會把數據庫中item1對應的記錄刪掉。
在多對多關係中不能夠把cascade設置爲all和delete,這樣問題就大了,想一想會有什麼後果。
unique屬性的用法:
之外間關聯的一對一,本質上變成了一對多的雙向關聯了,編寫以一對多和多對一要求編寫,最後在many-to-one這一邊加上unique="true"即說明它只不過是一對多的特例(「多」這一方只有一個對象)。
constrained屬性的用法:
對one-to-one關係進行延遲加載和其餘關係相比稍微有些不一樣。many-to-one的延遲加載是在配置文件的class標籤設置lazy="true",one-to-many和many-tomany的延遲加載在Set標籤設置lazy="true",而one-to-one不僅要在class標籤設置lazy="true",並且要在one-to-one標籤中設置constrained="true"。也就是說one-to-one關係,constrained="true"和附屬物的lazy="true"才能實現延遲加載,並忽略默認的預先抓取。(這裏說的是默認,若是指定fetch="join",則不管如何都是預先抓取)。
inverse屬性的用法:
兩個表設置了雙相關聯,inverse="true"表示雙方的關係將由對方去維護。
一對多應該讓「多」的這一端有主動權,也就是在「一」這一端設置inverse="true"。
多對多關聯關係中,若是雙方都有控制權,這時會有一些問題,好比雙方都引發插入語句,這就會違反數據庫的主鍵約束,緣由是試圖插入重複主鍵。說以在某一方設置inverse="true",而後在執行語句時使用主控方進行操做(也就是沒有設置inverse="true"的一方)。這樣就解決了。app