通過實例代碼講述Hibernate中inverse屬性與cascade屬性相關知識

Hibernate集合映射中,經常會使用到"inverse"和"cascade"這兩個屬性。對於我這樣,Hibernate接觸不深和語文水平夠爛的種種因素,發現這兩個屬性實在是難以理解,無奈只好將這個兩個屬性解釋工作交給了Google和Baidu,查看了許多牛人的解釋,加上自己在Eclipse上的調試,對"inverse"和"cascade"這兩個屬性有了一定的見解。

   "inverse"屬性探究

   "inverse"-直譯過來就是"反轉,使顛倒"的意思,書面化的解釋爲"是否將關係維護的權力交給對方"(這個解釋真夠蛋疼的-_-!!,就是理解不了)。 Hibernate中的"inverse"屬性只有兩個值"true"和"false"。"true"表示將關係維護的權力交給對方,"false"表示不交出維護權力(默認值)。

   例如有兩張表,customer和orders,他們的關係是一對多,customer是一方,orders爲多方。


   drop table if exists customer; 
   drop table if exists orders; 
   
   create table customer 
   ( 
       id varchar(255) not null, 
       username varchar(255), 
       password varchar(255), 
       age integer, 
       register_time datetime, 
       primary key (id) 
   ); 
   
   create table orders 
   ( 
       id varchar(255) not null, 
       orderNumber varchar(255), 
       balance integer, 
       customer_id varchar(255), 
       primary key (id) 
   ); 
   兩表對應的hbm文件,對應的POJO類:


   /*customer表對應的POJO類*/
   public class Customer 
   { 
       private String id; 
       private String username; 
       private String password; 
       private Timestamp registerTime; 
       private int age; 
       private Set<Order> orders = new HashSet<Order>(); 
   
       public Customer() 
       { 
   
       } 
   
       /*get and set method*/
   
   } 
   
   /*orders表對應的POJO類*/
   public class Order 
   { 
       private String id; 
       private String orderNumber; 
       private int balance; 
       private Customer customer; 
        
       public Order() 
       { 
            
       } 
   
       /* get and set method*/
   } 
  


   <!--Customer類的hbm文件--> 
       <hibernate-mapping> 
           <class name="com.suxiaolei.hibernate.pojos.Customer" table="customer"> 
               <id name="id" type="string"> 
                   <column name="id"></column> 
                   <generator class="uuid"></generator> 
               </id> 
                
               <property name="username" column="username" type="string"></property> 
               <property name="password" column="password" type="string"></property> 
               <property name="age" column="age" type="integer"></property> 
               <property name="registerTime" column="register_time" type="timestamp"></property> 
                
               <set name="orders" inverse="true" cascade="all"> 
                   <key column="customer_id" ></key> 
                   <one-to-many class="com.suxiaolei.hibernate.pojos.Order"/> 
               </set> 
            
           </class> 
       </hibernate-mapping> 
   
   <!--Order類的hbm文件--> 
       <hibernate-mapping> 
           <class name="com.suxiaolei.hibernate.pojos.Order" table="orders"> 
               <id name="id" type="string"> 
                   <column name="id"></column> 
                   <generator class="uuid"></generator> 
               </id> 
                
               <property name="orderNumber" column="orderNumber" type="string"></property> 
               <property name="balance" column="balance" type="integer"></property> 
                
               <many-to-one name="customer" class="com.suxiaolei.hibernate.pojos.Customer"> 
                   <column name="customer_id"></column> 
               </many-to-one>         
           </class> 
       </hibernate-mapping> 
下面寫一些測試代碼測試"inverse"屬性的特性:

   情況一:將"inverse"設置爲true,讓多方維護關係


   try
   { 
       tx = session.beginTransaction(); 
        
       /* 
        * 創建Customer對象,並設置其屬性值 
        */
       Customer customer = new Customer(); 
       customer.setUsername("zhangsan"); 
       customer.setPassword("123456"); 
       customer.setAge(22); 
       customer.setRegisterTime(new Timestamp(new Date().getTime())); 
        
       /* 
        * 創建Order對象order1,並設置其屬性值 
        */
       Order order1 = new Order(); 
       order1.setOrderNumber("a1a2a3"); 
       order1.setBalance(1000); 
       order1.setCustomer(customer);//將customer對象關聯到order1對象上 
        
       /* 
        * 創建Order對象order2,並設置其屬性值 
        */
       Order order2 = new Order(); 
       order2.setOrderNumber("d3d2d1"); 
       order2.setBalance(670); 
       order2.setCustomer(customer);///將customer對象關聯到order2對象上 
        
       customer.getOrders().add(order1);//將order1對象關聯到customer對象上 
       customer.getOrders().add(order2);//將order2對象關聯到customer對象上 
        
       session.saveOrUpdate(customer); 
        
       tx.commit(); 
   } 
   catch (Exception e) 
   { 
       if(tx != null) 
       { 
           tx.rollback(); 
       } 
        
       e.printStackTrace(); 
   } 
   finally
   { 
       session.close(); 
   } 
   數據庫中的數據更新爲:

   customer表:

   orders表: 

   現在將order1.setCustomer(customer);這段代碼註釋掉,再次運行程序:

   customer表:

   orders表:

   可以到看到顯著地差別了,第一次保存"id"="402881e534ea7c750134ea7c76bc0001"的數據時,orders表中插入了兩條數據,他們的customer_id都爲customer中對應記錄的主鍵值,而第二次保存記錄"id"="402881e534ea81be0134ea81bfea0001"的數據時,由於先前將原來的代碼段order1.setCustomer(customer);註釋掉了,此時order表中插入的數據中order1代表的那條記錄沒有customer_id值。

從以上現象可以有助於理解"inverse"這個屬性。首先,"inverse"控制關係維護權力,那麼什麼是"關係"?,關係的具體體現是什麼?在以上例子中,"關係"就是兩個表之間的關係,通常爲"一對多","一對一","多對多"三種關係,而關係的具體體現爲orders表中的 customer_id列,而"inverse"屬性就是告訴Hibernate哪一方有權力管理和維護這一列。上面的例子將"inverse"設置爲 true那麼customer_id這一列由多方(order對象)維護。這說明了,只有order對象對關係的操作會反映到數據庫中。(對象對關係的操作就是對關聯屬性的操作,例如order對象對自身的"customer"屬性操作,customer對象對自身的orders集合(Set<Order>)操作)

   例如,將id="402881e534ea7c750134ea7c76bc0001"的customer對象從數據庫中取出,獲取到該customer對象所關聯的order對象集合,將該customer對象所關聯的order對象刪除。


   Customer customer = (Customer)session.get(Customer.class, "402881e534ea7c750134ea7c76bc0001"); 
   Order order = (Order)session.get(Order.class, "402881e534ea7c750134ea7c76ce0002"); 
                
   System.out.println("customer association order count:"+customer.getOrders().size()); 
   customer.getOrders().remove(order); 
   System.out.println("customer association order count:"+customer.getOrders().size()); 
                
   session.saveOrUpdate(customer); 
   //Console Output:

   customer association order count:2
customer association order count:1

  

   可以看到customer中關聯的order對象集合確實有對象被刪除了,若操作有效,表示該order對象與customer對象沒有關係了,反映到數據庫中應該將該order對象對應的customer_id設置爲null。現在查看一下數據庫數據:

   看到了吧,剛剛那個操作就是個無用操作,不會反應到數據庫中。我們修改一下程序代碼:


   Customer customer = (Customer)session.get(Customer.class, "402881e534ea7c750134ea7c76bc0001"); 
   Order order = (Order)session.get(Order.class, "402881e534ea7c750134ea7c76ce0002"); 
                
   order.setCustomer(null); 
                
   session.saveOrUpdate(customer); 
   這次我們使用order對象來操作關係,將該order對象與customer對象脫離關係,若操作有效,則反映在數據庫中應該是該order對象的customer_id字段的值變成null,現在查看一下數據庫:

   可以看到,此次操作成功的反映到了數據庫中了。

   情況二:將"inverse"屬性設置爲"false",雙方都維護關係(因爲沒有一方交出權力,"inverse"的默認值爲"false",而且"inverse"屬性只能在set、list、map等幾個標籤中設置,像many-to-one這一類的標籤都不能設置"inverse"這個屬性值,它們只能取值"false")

   這裏會產生書中所說的性能問題(囧,這個也是理解了很久很久),這個不管怎麼說你都可能理解不了,我就是這樣的(-_-!!),所以我建議使用第三方的軟件將Hibernate輸出的SQL語句的綁定值顯示出來(可以參考這裏)。之所以會產生性能爲題,當你操作關係是會無故多產生一些update語句,比如你使用上面的例子保存一個customer對象,它關聯了2個order對象,它不但會生成3條insert語句(用於插入數據),還會生成2條update語句(將關聯的order對象的customer_id更新爲自己的主鍵值),你想想要是一個customer對象包含幾萬了order對象(購物狂),那麼每次保存它得要多生成幾萬條update語句,這個就是很嚴重的性能問題了。

   爲什麼Hibernate會產生update語句呢?那是Hibernate太主動,太熱情,太負責的表現,它怕你出現錯誤,例如有幾萬個order對象需要關聯到customer對象上,這就需要調用order.setCustomer(customer);,幾萬個對象這不是人可以不放錯的完成的。所以Hibernate怕你出錯忘記調用這個方法,所以他將會在order對象保存完畢後將所有關聯對象的customer_id字段更新一遍,確保正確性,這樣也就產生上面的性能問題。

   將"inverse"設置爲false後,你可以嘗試設置order1.setCustomer(null),它依然會正確的將customer的主鍵值完美的插入到order的customer_id字段上,只是會多一條update語句。

   "cascade"屬性

   "cascade"-直譯過來就是"級聯、串聯"的意思,書面化的解釋爲"該屬性會使我們在操作主對象時,同時Hibernate幫助我們完成從屬對象相應的操作(比如,有Customer和Order這兩張表,關係爲一對多,只使用JDBC刪除Customer表中的一行記錄時,我們還需要手動的將Order表中與之關聯的記錄全都刪除,使用Hibernate的'cascade'屬性後,當我們刪除一條Customer記錄時,Hibernate會幫助我們完成相應Order表記錄的刪除工作,方便了我們的工作)"。

   總 結

   使用"inverse"這個屬性時,要考慮清楚關係,不然你的系統就會有大的性能問題(不過我可能想不清楚,現在還是一個普通大學生沒什麼實戰經驗-_-!!,要繼續努力~_~),書本上和一些牛人建議,關係一般由"多方"維護,當遇到"多對多"時怎麼辦,其實多對多久是兩個"一對多",隨意設置一方"inverse"爲"true"就可以了,不要兩方都設置或都不設置(囧,我開始就是死板這樣的設置)。而是用"cascade"屬性時,主對象(一方)一般設置爲"all",而多方不建議設置包含delete操作的選項,建議設置多方爲"save-update",這是因爲你刪除一方,多方已經沒有存在的意義了,而刪除多方不能代表一方沒意義了(例如,消費者和訂單)。最後,"cascade"操作的是兩張表的記錄或兩端的對象,而"inverse"操作的是兩張表的關係或兩個對象的關係。

 

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