Hibernate中的cascade和inverse

這兩個屬性都用於一多對或者多對多的關係中。而inverse特別是用於雙向關係,在單向關係中我們並不需要。

 

Cascade代表是否執行級聯操作,Inverse代表是否由己方維護關係。

 

Cascade:

 

Cascade屬性的可能值有

    all: 所有情況下均進行關聯操作,即save-update和delete。
    none: 所有情況下均不進行關聯操作。這是默認值。
    save-update: 在執行save/update/saveOrUpdate時進行關聯操作。
    delete: 在執行delete 時進行關聯操作。

    all-delete-orphan: 當一個節點在對象圖中成爲孤兒節點時,刪除該節點。比如在一個一對多的關係中,Student包含多個book,當在對象關係中刪除一個book時,此book即成爲孤兒節點。

 

Inverse:

 

Inverse屬性的可能值是true或者false,默認爲false:

 

     false代表由己方來維護關係,true代表由對方來維護關係。在一個關係中,只能由一方來維護關係,否則會出問題(解疑中會講到);同時也必須由一方來維護關係,否則會出現雙方互相推卸責任,誰也不管。

 

一多對的例子:

 

有兩個類,Father和Child,是一對多的關係。下面這段hbm配置是從Father.hbm.xml中摘取的。

 

 

<set name="children" lazy="true" cascade="all" inverse="true"> <key column="fatherid"/> <one-to-many class="my.home.Child"/> </set>

 

我們知道cascade和inverse的值對會有四種組合的可能(在此僅先假定cascade值爲none或all)。

 

有如下一段代碼:

 

Java代碼 
  1. FatherDao fatherDao = new FatherDao();   
  2.   
  3. Father father = new Father("David");   
  4. Child child1 = new Child("David Junior One");   
  5. Child child2 = new Child("David Junior Two");   
  6.   
  7. father.add(child1);   
  8. father.add(child2);   
  9.   
  10. fatherDao.save(father);  

 

1. 如果cascade="all"且inverse="false"時:

 

此時可以看到log裏面:

 

Java代碼 
  1. // 執行對father的插入   
  2. Hibernate: insert into father (name) values (?)   
  3.   
  4. // cascade = 'all',所以進行級聯操作   
  5. Hibernate: insert into child (name, fatherid) values (?, ?)   
  6. Hibernate: insert into child (name, fatherid) values (?, ?)   
  7.   
  8. // inverse = 'false',由father來維護關係(可以看到這些操作是多餘的)   
  9. Hibernate: update child set fatherid =? where ID=?   
  10. Hibernate: update child set fatherid =? where ID=?  
 

2. 如果cascade = "none" 且 inverse = "false":

 

Java代碼 // 執行對father的插入   
  1. Hibernate: insert into father (name) values (?)   
  2.   
  3. // inverse='false',所以更新關係   
  4. Hibernate: update child set fatherid =? where ID=?   
  5.   
  6. // 但由於cascade='none',child並未插入數據庫,導致如下exception   
  7. org.springframework.dao.InvalidDataAccessApiUsageException: object references an unsaved transient instance  
 

3. 如果cascade = "all" 且 inverse = "true"

 

Java代碼 
  1. // 執行對father的插入   
  2. Hibernate: insert into father (name) values (?)   
  3.   
  4. // cascade='all',執行對child的插入   
  5. Hibernate: insert into child (name, fatherid) values (?, ?)   
  6. Hibernate: insert into child (name, fatherid) values (?, ?)   
  7.   
  8. // 但由於inverse='true',所以未有對關係的維護。但由於一對多的關係中,關係本身在“多”方的表中。所以,無需更新   
  9. 關係。  
 

4. 如果cascade = "none" 且 inverse = "true"

 

Java代碼 
  1. // 只執行對father的插入   
  2. Hibernate: insert into father (name) values (?)  
 

可以看到,對於一對多關係,關係應由“多”方來維護(指定“一”方的inverse爲true),並且應在“一”方指定相應的級聯操作。

 

多對多:

 

在多對多關係中,inverse可以爲任何一方,沒有什麼區別。

 

解疑:

 

爲什麼在多對多中不能由雙方都來維護關係了:因爲這樣會導致重複更新中間表的可能,報出重複值的錯誤。

 

那麼如何在多對多的雙向關聯中使雙方都能維護關係:最好讓控制關係的那方來更新關係,如果想讓另一方也來維護關係,那麼只有在操作這一方的數據時“顯式”更新中間表了吧。

 

注意:

 

同時注意在雙向關聯中,對象之間的關聯跟上面提及的關係表維護沒有關係。一個是對象/java層面的,一個是hibernate數據庫層面的。如果你想在更新一方時,也更新另一方的對象集合,請看下面這段代碼:

 

這是Person類中的一段代碼,Person和Event是多對多的雙向關聯關係,他們在對方類中的集合分別爲participants和events。關係表由Person維護,所以對象關係的維護也在Person類中,而不是Event類中。

 

Java代碼 複製代碼
  1. public void addToEvent(Event event) {   
  2.         this.getEvents().add(event);   
  3.         event.getParticipants().add(this);   
  4. }   
  5.   
  6. public void removeFromEvent(Event event) {   
  7.         this.getEvents().remove(event);   
  8.         event.getParticipants().remove(this);   
  9. }  
發佈了140 篇原創文章 · 獲贊 10 · 訪問量 40萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章