Hibernate學習日誌二--cascade和inverse分析

在自己理解的基礎上,然後結合hibernate 的文檔,重新總結下這兩個屬性。。。如有錯誤,請給予指正,謝謝。。

 

1、cascade(級聯)

   引用了《深入淺出 Hibernate》:級聯(cascade)在Hibernate映射關係中,它指的是當主控方執行操作時,關聯對象(被動方)是否同步執行同一操作,如主控方對象調用save-update或delete 方法時,是否同事對關聯對象(被動方)進行save-update或delete。

  這裏所說的主控方按我理解指的是:比如,User 類中有一Address屬性,User和Address 是一對多的關係,然後當user.save(address);的時候,user就是主控方了。

 

2、inverse(控制方向反轉)

   引用了《深入淺出 Hibernate》:在Hibernate 語義中,inverse指定了關聯關係中的方向。關聯關係中,inverse=false 的爲主動方,由主動方負責維護關聯關係。

   這裏所說的關聯關係按我理解指的是:爲了維持兩個實體類(表)的關係,而添加的一些屬性,該屬性可能在兩個實體類(表)或者在一個獨立的表裏面,這個要看這雙方直接的對應關係了:

ps:這裏的維護指的是當主控放進行增刪改查操作時,會同時對關聯關係進行對應的更新。

   一對多:該屬性在多的一方。應該在一方的設置 inverse=true ,多的一方設置 inverse=false(多的一方也可以不設置inverse屬性,因爲默認值是false),這說明關聯關係由多的一方來維護。原因:該關聯關係的屬性在多的一方的表中,在維護關聯關係的時候在多的一方容易維護。

   多對多:屬性在獨立表中。在任意一方設置inverse=true,另一方inverse=false;原因:如果兩個多設置爲true 的話,表示兩方都對關聯關係表(獨立表)進行了同樣的維護,其實只要一方維護就行了,效率上來說,這樣設置是合理點的。

   一對一:其實是一對多的一個特例,inverse 的設置也是一樣的,主要還是看關聯關係的屬性在哪一方,這一方的inverse=false。

   多對一:也就是一對多的反過來,沒什麼區別。

----------------------------------------------------------------------------------------------------------------------------

 下面開始一個一對多雙向關聯的父子關係的例子,通過例子可以很好的理解這兩者的概念.

 

父子類:

Java代碼 複製代碼
  1. public class Child {   
  2.     private int id;   
  3.     private String name;   
  4.     private Parent parent;   
  5.     public int getId() {   
  6.         return id;   
  7.     }   
  8.   
  9.         ````    other   geter 、setter`````   
  10. }   
  11.   
  12. ---------------------------------------------------------   
  13. public class Parent {   
  14.     private int id;   
  15.     private String name;   
  16.     private Set children;   
  17.     public int getId() {   
  18.         return id;   
  19.     }   
  20.         ````    other   geter 、setter`````   
  21. }  
 

 

配置文件:

Xml代碼 複製代碼
  1. <hibernate-mapping>  
  2.   <class name="model.Child">  
  3.     <id name="id">  
  4.       <generator class="native"></generator>  
  5.     </id>  
  6.     <property name="name"></property>  
  7.     <many-to-one name="parent" column="parent_id" ></many-to-one>  
  8.   </class>  
  9. </hibernate-mapping>  
  10.   
  11.   
  12.   
  13. <hibernate-mapping>  
  14.  <class name="model.Parent" >  
  15.    <id name="id">  
  16.      <generator class="native"></generator>  
  17.    </id>  
  18.    <property name="name" />  
  19.    <set name="children" cascade="all" inverse="true" >//請注意這裏的變化   
  20.      <key column="parent_id"/>  
  21.      <one-to-many  class="model.Child"/>  
  22.    </set>  
  23.  </class>  
  24. </hibernate-mapping>  

 

測試代碼:

Java代碼 複製代碼
  1. public void testSaveParent(){   
  2.     Session session=HibernateUtils.getSession();   
  3.        
  4.     session.beginTransaction();   
  5.        
  6.     Parent parent=new Parent();   
  7.        
  8.     Child child=new Child();       
  9.     child.setName("child");   
  10.     child.setParent(parent);   
  11.            //session.save(child);   
  12.        
  13.     Set children=new HashSet();   
  14.     children.add(child);   
  15.        
  16.     parent.setName("parent");   
  17.     parent.setChildren(children);   
  18.     //保存parent   
  19.     session.save(parent);   
  20.        
  21.     session.flush();   
  22.     session.getTransaction().commit();   
  23.        
  24. }  
 

 

下面分幾種情況對上面配置文件中注意的地方進行修改:

 

 

1、不設置cascade和inverse 屬性

Xml代碼 複製代碼
  1. <set name="children" >  

 日誌中發出的兩條語句和出錯信息:

Java代碼 複製代碼
  1. Hibernate: insert into Parent (name) values (?)   
  2. Hibernate: update Child set parent_id=? where id=?   
  3. 953  [main] ERROR org.hibernate.event.def.AbstractFlushingEventListener  - Could not synchronize database state with session   
  4. org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: model.Child  
 

 分析:第一條語句是保存parent ,因爲測試代碼中,session.save(parent);,使得parent 從瞬時對象轉到持久對象,並同步到數據庫中,第二條語句是更新parent,因爲parent 在維護關係,往而child表更新parent_id,但發現child不存在,所以發生了錯誤,(在事務打開到事務結束整個過程 child 還是瞬時對象),如果在session.save(parent);之前,進行session.save(child);,也對child 變成持久對象的話,就不會發生錯誤了,如下信息,會產生四條語句,兩天插入語句,兩天更新語句(兩者都在維護關係)。

Xml代碼 複製代碼
  1. Hibernate: insert into Child (name, parent_id) values (?, ?)   
  2. Hibernate: insert into Parent (name) values (?)   
  3. Hibernate: update Child set name=?, parent_id=? where id=?   
  4. Hibernate: update Child set parent_id=? where id=?  

 

2、只設置inverse屬性

Xml代碼 複製代碼
  1. <set name="children" inverse="true" >  

 日誌中發出一條語句:

Xml代碼 複製代碼
  1. Hibernate: insert into Parent (name) values (?)  

 分析:雖然設置了inverse=true 把關係的維護交給了child 來維護,但在事務打開到事務結束整個過程,child 一直都是個瞬時對象,由於沒有涉及到child,所以沒有發生錯誤。

 

3、只設置cascade 屬性

Xml代碼 複製代碼
  1. <set name="children" cascade="all"  >  

 日誌中發出三條語句:

Xml代碼 複製代碼
  1. Hibernate: insert into Parent (name) values (?)   
  2. Hibernate: insert into Child (name, parent_id) values (?, ?)   
  3. Hibernate: update Child set parent_id=? where id=?  

  分析:由於設置了cascade級聯屬性,第一條語句是保存了parent ,然後保存parent的時候由於設置了級聯屬性,發現child沒有保存,會先保存child(該語句也包括child維護關係),所以發出了第二條語句,真正parent維護關係的時候是第三條語句。

 

4、同時設置cascade 屬性和inverse屬性

Xml代碼 複製代碼
  1. <set name="children" cascade="all" inverse="true" >  

 日誌中發出兩條語句:

Xml代碼 複製代碼
  1. Hibernate: insert into Parent (name) values (?)   
  2. Hibernate: insert into Child (name, parent_id) values (?, ?)  

  分析:第一條語句是由於保存parent 發出的,第二條語句是由於parent時候由於設置了級聯屬性,而發出的。相對與3 的結論,少了一條parent 維護關係的語句,是因爲parent中設置了inverse="true" ,因此parent不維護關係了,而由child維護。

 

總結:

  在一對多的關聯關係中,合理的設置cascade 屬性和inverse屬性,可以達到數據庫優化的效果,大大提高了程序的性能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章