hibernate裡inverse和cascade的理解

roszhaodan481發表於2014-05-23

首先,來看inverse和cacade的取值有哪些..
1. cascade 有五個選項 分別是: all ,delete ,none,save-update,delete-orphan ;
2. inverse 有兩個值 true ,false
這幾個值各是什麼呢?
cascade的五個值:
        all:所有情況下均進行關聯操作,即save-update + delete.
        none:所有情況下均不進行關聯操作。這是預設值。
        save-update:在執行save/update/saveOrUpdate時進行關聯操作。
        delete:在執行delete時進行關聯操作。
        delete-orphan: 當save/update/saveOrUpdate時,相當於save-update;刪除時,相當於delete
還有個 all-delete-orphan :是當物件圖中產生孤兒節點時,在資料庫中刪除該節點 。//不太明白

inverse:ture 表示主控權交給關聯類來執行
         false預設值 ,由自己來行駛主控權

 inverse屬性預設是false的,就是說關係的兩端都來維護關係。這個意思就是說,如有一個Student,  Teacher和TeacherStudent表,Student和Teacher是多對多對多關係,這個關係由TeacherStudent這個表來表 現。那麼什麼時候插入或刪除TeacherStudent表中的記錄來維護關係呢?在用hibernate時,我們不會顯示的對 TeacherStudent表做操作。對TeacherStudent的操作是hibernate幫我們做的。hibernate就是看hbm檔案中指 定的是"誰"維護關係,那個在插入或刪除"誰"時,就會處發對關係表的操作。前提是"誰"這個物件已經知道這個關係了,就是說關係另一頭的物件已經set 或是add到"誰"這個物件裡來了。前面說過inverse預設是false,就是關係的兩端都維護關係,對其中任一個操作都會處發對錶系表的操作。當在關係的一頭,如Student中的bag或set中用了inverse="true"時,那就代表關係是由另一關維護的(Teacher)。就是說當這插入Student時,不會操作TeacherStudent表,即使Student已經知道了關係。只有當Teacher插入或刪除時才會處發對關係表的操作。所以,當關系的兩頭都用inverse="true"是不對的,就會導致任何操作都不處發對關係表的操作。當兩端都是inverse= "false"或是default值是,在程式碼對關係顯示的維護也是不對的,會導致在關係表中插入兩次關係。

  在一對多關係中inverse就更有意義了。在多對多中,在哪端inverse="true"效果差不多(在效率上)。但是在一對多中,如果要一方維護關係,就會使在插入或是刪除"一"方時去update"多"方的每一個與這個"一"的物件有關係的物件(注意:這裡所指的有關係一般是指的設定多方的ID屬性,使之與一方的關聯在一起)。而如果讓"多"方面維護關係時就不會有update 操作,因為關係就是在多方的物件中的,直指插入或是刪除多方物件就行了。當然這時也要遍歷"多"方的每一個物件顯示的操作修關係的變化體現到DB中。不管 怎樣說,還是讓"多"方維護關係更直觀一些。
    (1)對one-to-many而言,改變set,會讓hibernate執行一系列的update語句,不會delete/insert資料
    (2)對many-to-many而言,改變set,只修改關係表的資料,不會影響many-to-many的另一方。
    (3)雖然one-to-many和many-to-many的資料庫操作不一樣,但目的都是一個:維護資料的一致性。   
 

測試:
一對多關係的兩張表:boy、girl(一個男孩可以多個女朋友)
boy表結構
Field   Type        
------  -----------
name    varchar(50)  pk
age     varchar(50)
girl表結構
Field   Type        
------  -----------
name    varchar(50)  pk
bf      varchar(50)  fk

【儲存時:Inverse與cascade】
建立三個girl物件和一個boy物件,讓這是三個girl都是boy的女朋友
  ---------建立物件的程式碼片段-----------
  Boy boy = new Boy("tom","23", null);
  Set girls = new HashSet();
  
  Girl g[] = new Girl[]{
                        new Girl("Alice1", boy),
                        new Girl("Alice2", boy),
                        new Girl("Alice3", boy)

                        };
  girls.add(g[0]);
  girls.add(g[1]);
  girls.add(g[2]);
  
  boy.setGirls(girls);
  session.save(boy);
在Boy.hbm.xml中設定,
1.Inverse = true,不指定cascade 既為none
   cascade的預設值為none, 當對boy進行儲存操作時,girl什麼都不做. 所以只儲存了boy物件, 沒有儲存girl物件
2.Inverse = true,cascade=all (由多方來維護關係,那麼不需要update,因為它關係就在它那兒)
   boy與girl物件,包擴外來鍵都成功儲存。只不過girl表中的對應的id是null
   (SELECT 3, INSERT 4)
3.Inverse = false,不指定cascade,既為none
   報錯。因為boy為主控方,負責維護關係,在維護關係是發現並不存在girl記錄,所以不能建立關係。
4.Inverse = false,cascade=all   (由一方維護關係,那麼會產生update)
   boy與girl物件,包擴外來鍵都成功儲存。
   (SELECT 3, INSERT 4, UPDATE 3)
   分析:除了4條INSERT語句之外,其他的6條語句是我們為了圖方便付出的代價:3條SELECT語句用來判斷girl物件是否在資料表中已經存在,3條UPDATE語句是為了維護外來鍵關係
高效率的做法:在Boy.hbm.xml中設定Inverse=true,在Girl.hbm.xml中設定cascade=all,然後儲存三個girl物件
(SELECT 1, INSERT 4)
   高效率的代價就是儲存的時候比較麻煩
【刪除時:Inverse與cascade】
希望通過刪除boy,也將3個girl物件刪除。程式中先查出boy物件,然後進行刪除
  -----------------------------------------
  Boy boy = (Boy) s.get(Boy.class, "tom");
  s.delete(boy);
  -----------------------------------------
同樣在Boy.hbm.xml中進行設定
1.Inverse = true  cascade = none
   可以猜到結果是出錯。原因:外來鍵約束錯誤,他沒有維護關係,所以引起外間衝突
2.Inverse = false  cascade = none                
   boy刪除,girl表中外來鍵變為null,沒有刪除記錄 ;  
(UPDATE 1, DELETE 1)
3.Inverse = false, cascade = all
          全部刪除  ;在刪除有外來鍵的從表時,先把從表外來鍵置為null,然後刪除主表記錄,最後根據從表主鍵刪除所有相關從表記錄
   (UPDATE 1, DELETE 4)
4.Inverse = true, cascade = all
          全部刪除
   (DELETE 4)
Inverse是hibernate雙向關係中的基本概念,當然對於多數實體,我們並不需要雙向關聯,更多的可能會選擇單向關聯,況且我們大多數人一般採用一對多關係,而一對多雙向關聯的另一端:多對一的inverse屬性是不存在,其實它預設就是inverse=false.從而防止了在一對多端胡亂設定inverse也不至於出錯。但是inverse設定不當確實會帶來很大的效能影響,這點是我們必須關注的。

看了這篇文章,還是很有必要再寫下一些總結的:
1)inverse中提及的side其實是指一個類或者表的概念,雙向關聯其實是指雙方都可以取得對方的應用。
2)維護關係這個名詞還是稍顯模糊或者晦澀。我們一般說A類或者A表(這裡的表的是指多對多的連線表)有責任維護關係,其實這裡的意思是說,我在應用在更新,建立,刪除(讀就不用說了,雙向引用正是為了方便讀而出現)A類或者A表時,此時建立的SQL語句必須有責任保證關係的正確修改。
3)inverse=false的side(side其實是指inverse=false所位於的class元素)端有責任維護關係,而inverse=true端無須維護這些關係。
4)我們說inverse設立不當會導致效能低下,其實是說inverse設立不當,會產生多餘重複的SQL語句甚至致使JDBC exception的throw。這是我們在建立實體類關係時必須需要關注的地方。一般來說,inverse=true是推薦使用,雙向關聯中雙方都設定 inverse=false的話,必會導致雙方都重複更新同一個關係。但是如果雙方都設立inverse=true的話,雙方都不維護關係的更新,這也是不行的,好在一對多中的一端:many-to-one預設是inverse=false,避免了這種錯誤的產生。但是對多對就沒有這個預設設定了,所以很多人經常在多對多的兩端都使用inverse=true,結果導致連線表的資料根本沒有記錄,就是因為他們雙方都沒有責任維護關係。所以說,雙向關聯中最好的設定是一端為inverse=true,一端為inverse=false。一般inverse=false會放在多的一端,那麼有人提問了, many-to-many兩邊都是多的,inverse到底放在哪兒?其實hibernate建立多對多關係也是將他們分離成兩個一對多關係,中間連線一個連線表。所以通用存在一對多的關係,也可以這樣說:一對多是多對多的基本組成部分。

詳細頁面:http://www.verydemo.com/demo_c146_i31397.html

相關文章