正確理解hibernate的inverse!

在hibernate中是通過inverse的設置來決定是有誰來維護表和表之間的關係的
 
Inverse是hibernate雙向關係中的基本概念,當然對於多數實體,我們並不需要雙向關聯,更多的可能會選擇單向關聯,況且我們大多數人 一般採用一對多關係,而一對多雙向關聯的另一端:多對一的inverse屬性是不存在,其實它默認就是inverse=false.從而防止了在一對多端 胡亂設置inverse也不至於出錯。但是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建立多對多關係也是將他們分離成兩個一對多關係,中間連接一 個連接表。所以通用存在一對多的關係,也可以這樣說:一對多是多對多的基本組成部分。
看下面的多對多的定義大家更會清楚”多對多“與“一對多”的關係:其中我們注意<many-to-many />標籤的特點就知道,它是定義了一個多對多關係,而不是<one-to-many/>。
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC    
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping package="org.hibernate.auction">
<class name="TestA" table="TestA"    
dynamic-update="true" dynamic-insert="true" >

     <id name="id" column="id" type="int" unsaved-value="any" >    
        <generator class="assigned">    
        </generator>    
     </id>

     <property name="name" type="java.lang.String"    
        update="true" insert="true" column="name" />

     <set name="testBs" table="TestA_TestB" inverse="false" cascade="all">    
        <key column="testA"/>    
        <many-to-many column="testB" class="TestB" />    
     </set>

 
</class>    
<class name="TestB" table="TestB"    
dynamic-update="true" dynamic-insert="true" >

     <id name="id" column="id" type="int" unsaved-value="any" >    
        <generator class="assigned">    
        </generator>    
     </id>

     <property name="name" type="java.lang.String" update="true"    
     insert="true" column="name" />

     <set name="testAs" table="TestA_TestB" inverse="true" cascade="all">    
        <key column="testB"/>    
        <many-to-many column="testA" class="TestA" />    
     </set>


</class>    
</hibernate-mapping>
在對多對中,因爲一端維護關係另一端不維護關係的原因,我們必須注意避免在應用中用不維護關係的類建立關係,因爲這樣建立的關係是不會在數據庫中存儲的。基於上面的映射文件代碼給出一個例子:
package org.hibernate.auction;
import java.util.*;

/**
* @author Administrator
*
* To change the template for this generated type comment go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/

public class TestA {
int id;
String name;
Set testBs=new HashSet();
public TestA(){
    
}
public TestA(int id){
     setId(id);
}
public int getId(){
     return id;
}
public void setId(int id){
     this.id=id;
}
public String getName(){
     return name;
}
public void setName(String name){
     this.name=name;
}
public Set getTestBs(){
     return testBs;
}
public void setTestBs(Set s){
     testBs=s;
}
public void addTestB(TestB tb){
     testBs.add(tb);
}

public static void main(String[] args) {
}
}

public class TestB {


int id;
String name;
Set testAs=new HashSet();
public TestB(){
    
}
public TestB(int id){
     setId(id);
}
public int getId(){
     return id;
}
public void setId(int id){
     this.id=id;
}
public String getName(){
     return name;
}
public void setName(String name){
     this.name=name;
}
public Set getTestAs(){
     return testAs;
}
public void setTestAs(Set s){
     testAs=s;
}
public void addTestA(TestA ta){
     testAs.add(ta);
}
public static void main(String[] args) {
}
}

測試代碼:
public void doTest() throws Exception{
     TestA a1=new TestA(1);
     TestA a2=new TestA(2);
     TestA a3=new TestA(3);
     TestB b1=new TestB(1);
     TestB b2=new TestB(2);
     TestB b3=new TestB(3);
     a1.addTestB(b1);
     a1.addTestB(b2);
     a1.addTestB(b3);
     b2.addTestA(a1);
     b2.addTestA(a2);
    
     Session s = factory.openSession();
    
     s = factory.openSession();
    
    
     Session session = factory.openSession();    
session.save(a1);    
session.flush();    
session.close();

}
測試後連接表的數據爲:
testa              testb
1                  1
1                  2
1                  3
根據inverse規則,對這些代碼:b2.addTestA(a1);   b2.addTestA(a2); 建立的關係,數據庫並沒有存儲下來,因爲TestB沒有責任維護這些關係,所以產生的sql語句自然不會有針對Testa_testB表的操作了。假設應 用中真的需要這些方法,那麼我們可以修改TestB的方法,讓他們注意在維護端類中執行相應的操作以使得關係能夠在數據庫中保存下來,更改TestB如 下:
/*
* Created on 2004-7-25
*
* To change the template for this generated file go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/

package org.hibernate.auction;
import java.util.*;

/**
* @author Administrator
*
* To change the template for this generated type comment go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/

public class TestB {


int id;
String name;
Set testAs=new HashSet();
public TestB(){
    
}
public TestB(int id){
     setId(id);
}
public int getId(){
     return id;
}
public void setId(int id){
     this.id=id;
}
public String getName(){
     return name;
}
public void setName(String name){
     this.name=name;
}
public Set getTestAs(){
     return testAs;
}
public void setTestAs(Set s){
     testAs=s;
}
public void addTestA(TestA ta){
     testAs.add(ta);
     ta.addTestB(this);
}
public static void main(String[] args) {
}
}

那麼測試執行後連接表的數據爲:
testa          testb
1               2
1               3
1                1
2                 2
測試通過。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章