一.簡介
在進行關系型資料庫設計時,表與表之間的關系往往不是獨立的,而是互相關聯的,這就是所謂的多表設計。一般來說,資料庫表與表包含以下幾種關系。

建表原則
一對一:主鍵對應,一方的主鍵作為另一方的主鍵。
一對多:在多的一方建立外鍵指向一的一方的主鍵
多對多:建立一個中間表,中間表的最少兩個字段作為外鍵分别指向多對多雙方的主鍵。
此種關系在hibernate中用Java對象表示如下:
class A class A class A
B b; Set<B> bs; Set<B> bs
} } }
class B class B class B
A a; Set<A> as
A a; } }
}
一對一的關系 一對多的關系 多對多的關系
在一般情況下,一對多的情況是比較常見的,比如學生與老師的關系,部門與員工的關系,客戶與聯系人的關系,是以,下面将以一對多關系為例說明hibernate是怎麼建立多表之間的關系的。
二.hibernate的一對多關系映射操作執行個體
1.例子說明:
本執行個體建立兩個表,分别是聯系人表和客戶表(典型的客戶管理系統中經常遇到的),其中一個客戶擁有多個聯系人,即客戶與聯系人的關系為一對多。是以,聯系人中存在外鍵,該外鍵指向客戶。具體描述如下。
2.建立hibernate實體
聯系人實體
private Long lkm_id;
private Character lkm_gender;
private String lkm_name;
private String lkm_phone;
private String lkm_email;
private String lkm_qq;
private String lkm_mobile;
private String lkm_memo;
private String lkm_position;
//注意這裡是關鍵寫法,在多的一方的實體中建立一個類型為一的一方的屬性
private Customer customer ;
get方法....
set方法....
}
客戶實體
public class Customer {
private Long cust_id;
private String cust_name;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_linkman;
private String cust_phone;
private String cust_mobile;
//注意這裡是關鍵,在一的一方的實體中建立一個泛型類型為多的一方的set集合。
private Set<LinkMan> linkMens = new HashSet<LinkMan>();
}
2.建立映射關系
聯系人映射關系的寫法(多的一方)
前面普通字段不再累述,可參見筆者前一篇部落格。重點講述關聯對象的配置。一的一方使用many-to-one元素。
<many-to-one name="customer" column="lkm_cust_id" class="Customer的完整類名" >
</many-to-one>
name屬性:引用屬性名
column屬性: 外鍵列名
class屬性: 與我關聯的對象完整類名
客戶映射關系的寫法(一的一方)
多的一方使用set元素來描述被映射類的set集合,
<set name="linkMens" >
<key column="lkm_cust_id" ></key>
<one-to-many class="LinkMan的完整類名" />
</set>
key标簽的column屬性:用來描述對應檔案多的一方的主鍵名稱。
one-to-many元素 的class屬性:用來描述映射關聯類
3.将映射添加到hibernate主配置檔案中
<mapping resource="Customer.hbm.xml檔案的包路徑" />
<mapping resource="LinkMan.hbm.xml的包路徑" />
4.編寫測試函數
public void text(){
//1 獲得session
Session session = HibernateUtils.openSession();
//2 開啟事務
Transaction tx = session.beginTransaction();
//-------------------------------------------------
//建立一個客戶
Customer c = new Customer();
c.setCust_name("谷歌");
//建立多個聯系人
LinkMan lm1 = new LinkMan();
lm1.setLkm_name("crc");
LinkMan lm2 = new LinkMan();
lm2.setLkm_name("psl");
//表達一對多,客戶下有多個聯系人
c.getLinkMens().add(lm1);
c.getLinkMens().add(lm2);
//表達對對對,聯系人屬于哪個客戶
lm1.setCustomer(c);
lm2.setCustomer(c);
//若無設定級聯操作,則所有對象均要儲存,否則出現瞬時對象異常。
session.save(c);
session.save(lm1);
session.save(lm2);
//4送出事務
tx.commit();
//5關閉資源
session.close();
}
若制定Junit測試後為綠條,且資料庫新建立兩個表,說明hibernate執行多表關聯操作成功。
三.hibernate多表關系映射的級聯操作
所謂級聯操作是指當主要方執行儲存,更新,删除操作時,其關聯的對象也會執行相同的操作。在映射檔案中通過set元素的
屬性cascade來配置。主要方的選擇是任意的,但一般習慣主要方選擇為一的一方。
1.級聯儲存,關鍵詞為save-update
配置如下代碼:
<set name="linkMens" cascade="save-update" >
<key column="lkm_cust_id" ></key>
<one-to-many class="LinkMan" />
</set>
此時,隻要執行儲存客戶,聯系人會跟着儲存下來。
2.級聯删除,關鍵詞為delete
配置代碼如下
<set name="linkMens" cascade="delete" >
<key column="lkm_cust_id" ></key>
<one-to-many class="LinkMan" />
</set>
這時,在代碼中删除了客戶,與其關聯的聯系人也會跟着删除,但是,要注意,這種操作比較危險,一般不用。
要注意,級聯儲存和級聯删除是可以同時配置 的。
四.雙向關聯産生多餘的SQL語句 的問題
在實行表對象關聯時操作時,SQL語句有可能會重複執行,出現這種問題的原因是,兩個表對象都維護了關系,持久化對象可以自動更新資料庫,更新客戶時會修改一次外鍵,更新聯系人時也會修改一次外鍵,是以産生多餘的SQL語句。解決方法是使其中一方放棄維護關系即可。一般情況下,一的一方放棄維護關系。執行如下配置即可。
<set name="linkMens" inverse="true" cascade="delete,save-update" >
<key column="lkm_cust_id" ></key>
<one-to-many class="LinkMan" />
</set>
inverse的預設值為false,代表不放棄外鍵維護權,修改為true,即放棄維護。(注意, 這一點與我們的正常思維相反)
五.總結
資料庫的多表設計問題是一個重要的知識點,本部落格以一對多關系為例,介紹了hibernate中的多表操作。感興趣的朋友可以
深入研究多對多的表關系,或者三表以及更多表的hibernate操作。