HIbernate知識點複習之三
案例需求描述:
存在着一個客戶對應多個聯繫人的情況,單獨在聯繫人管理模塊中對聯繫人信息進行維護,功能包括:
對聯繫人信息進行增刪改查
表關係分析:
一 概述:數據庫中多表之間存在着三種關係:一對一 一對多 多對多 ,這也是系統設計中三種實體關係。
二 建表原則
1 一對多:在多的一方 創建外鍵指向一得一方的主鍵
2 多對多:創建一箇中間表,中間表裏創建至少兩個字段作爲外鍵,分別指向多對多雙方的主鍵
3 一對一:
(1)主鍵對應:一方主鍵作爲另一方主鍵
(2)唯一外鍵:一方創建外鍵字段 指向另一方的主鍵
三Hibernate通過java對象描述數據表的關係:
一 對 一
class A{ class B{
B b; A a;
getter和setter方法 getter和setter方法
} }
一 對 多
class A{ class B{
Set<B> b=new HashSet<B>(); A a;
getter和setter方法 getter和setter方法
} }
多 對 多
class A{ class B{
Set<B> b;=new HashSet<B>(); Set<A> a=new HashSet<A>();
getter和setter方法 getter和setter方法
} }
多表關係映射配置:
一 一對多配置
1. 一對多的一方:
頭標籤<set name="" cascade="" inverse=""></set>
<set>對應着一方實體中關聯多方的set集合屬性,如果是list集合屬性,對應的就是<list>
<set>元素的屬性:
(1)name(必填) :實體中對應的集合名稱
(2) cascade級聯操作屬性:
<1>級聯操作概念:級聯操作是指當主控方執行 保存,更新,刪除操作時,其關聯對象(被控方)也執行相同的操作,簡化操作,少寫代碼
<2>cascade屬性值:
* save-update:級聯保存更新
多表操作時,保存一方/主控方(如:客戶)的內容,又更新多方(如:聯繫人)的信息
特性:1》只保存一方的問題
2》具有方向性,保存一方同時更新另一方
存在情況:當雙方都設置了save-update,則會雙方都會執行對應關聯的sql語句,從而產生多餘sql語句。
* delete:級聯刪除,刪除一方的同時,也刪除多方的信息
概述:使用JDBC刪除客戶和聯繫人時,如果有外鍵的關係是不可以刪除的。但Hibernate可以實現這樣的功能。
但使用Hibernate刪除有關聯關係對象(如,客戶)的默認情況,會先將關聯關係的外鍵設置爲null,再刪掉客戶對象。
刪除的方式:
1》客戶一方不放棄維護外鍵 inverse="false" ,且沒有設置刪除級聯,屬於默認情況時,若直接刪除客戶則
會把客戶的關聯的外鍵 設置爲null再刪。
2》客戶一方不放棄維護外鍵 inverse="false",設置了刪除級聯,若直接刪除客戶,會把客戶關聯的(在另一張表的)聯繫人信息也刪掉
3》客戶一方放棄維護外鍵 inverse="true" 時,必須要設置刪除級聯纔可進行刪除
* all:save-update + delete
(3)inverse:配置關係是否維護
<1>概述:雙向關聯會產生多餘的sql語句,如下面的例子
//將2號聯繫人關聯的客戶改爲2號客戶
Customer customer = session.get(Customer.class,2L);
LinkMan linkMan = session.get(LinkMan.class,2L);
//雙向關聯
linkMan.setCustomer(customer);
customer.getLinkMans().add(linkMan);
此代碼會出現兩個重複(更新外鍵)的update語句,
原因爲:進行雙向維護關係時,持久態對象可自動更新到數據庫,更新客戶時會修改一次外鍵,
更新聯繫人時也會修改一次外鍵,從而產生多餘的sql語句
解決方案:只需一方放棄外鍵維護權即可(inverse="true"),也就是說關係不是雙方維護的,只需交給一方去維護即可
而一對多時,通常由多方進行關係維護(如老師對學生時,每個學生記住一個老師名字容易於一個老師記住全部學生名字)
<2>原則:必須要有一方維護關係,如在 一對多關係中,只能是一方 放棄維護關係(inverse="true"),多方不能放棄維護
<3>取值:默認值爲false,代表不放棄外鍵維護權,true爲放棄外鍵維護權
(4)區分cascade和 inverse:
casacde強調的是操作一個對象時,是否還操作其關聯對象
inverse強調的是外鍵的維護權
<set>標籤的子標籤:
(1)<key column="" ></key> column對應關聯多方(set方)的數據庫的外鍵名稱
(2)<one-to-many class=""/>class 對應關聯多方的實體全類名
一對多中一方的配置示例:
<set name="linkMans" inverse="true" cascade="save-update"> //放棄維護權,級聯保存更新
<key column="lkm_cust_id" />
<one-to-many class="XXXX.ZZZ.LinkMan"/>
</set>
2. 一對多的多方:
<many-to-one name="customer" column="lkm_cust_id" class="Customer" cascade="save-update"></many-to-one>
name:多方實體中關聯對象的屬性名稱
column:關聯實體的在數據庫中對應的外鍵名
class:關聯實體的全類名
cascade:級聯設置
二多對多:
1. 多對多的配置:
(1)配置模板:
<set name="roles" table="sys_user_role" cascade="save-update">
<key column="user_id"></key>
<many-to-many class="xx.xxx.Role" column="role_id"></many-to-many>
</set>
(2)<set>標籤:
name:關聯另一方的集合屬性名稱
table:中間表名稱
(3)<key>標籤:
column:當前對象在中間表的外鍵名稱
(4)<many-to-many>標籤:
class:關聯另一方的實體全類名
column:關聯另一方對應的外鍵
2. 多對多的外鍵維護問題:
(1)概述:在多對多的保存操作中,如果進行雙向關係維護,就必須要有一方放棄外鍵維護權。
原因分析: 因爲中間表作爲 關係維護紐帶
若兩張表都進行關係維護,則中間表的外鍵錄入每次都不能確定唯一的 主鍵,會出現 2對1的尷尬,會報錯:
解決方案爲:
1 不書寫維護雙向關係代碼
2 在某方配置文件中進行 inverse="true"配置
(2)總結:
一般是由被動方放棄,如用戶對角色,角色是被選中,所以角色要放棄外鍵維護權。
但如果進行單向關係維護,就不需任意放棄外鍵維護權。
3. 多對多的級聯配置:
多對多進行保存操作時,不可以保存一方,所以必須要進行保存更新級聯配置(cascade="save-update")
4. 多對多的其他操作:
(1)刪除用戶關聯的角色
//查詢2號用戶
User user = session.get(User.class,2L);
//查詢1號聯繫人
Role role=session.get(Role.class,1L);
//操作集合,相當於操作中間表
user.getRoles().remove(role);
(2)將某個用戶的角色改選
//查詢2號用戶
User user = session.get(User.class,2L);
//查詢1號聯繫人
Role role=session.get(Role.class,1L);
//查詢2號聯繫人
Role role2=session.get(Role.class,2L);
//操作集合,相當於操作中間表
user.getRoles().remove(role);
user.getRoles().add(role2);
(3)給某個用戶添加新角色
//查詢2號用戶
User user = session.get(User.class,2L);
//查詢1號聯繫人
Role role=session.get(Role.class,1L);
//操作集合,相當於操作中間表
user.getRoles().add(role);
一對多 和 多對多配置比較:
一 (Customer) 對 多(LinkMan)
private Set<LinkMan>linkMans=new HashSet<LinkMan>(); private Customer customer;
<set name="linkMans" inverse="false" cascade="save-update"> <many-to-one name="customer" column="lkm_cust_id" class="Customer" >
<key column="lkm_cust_id" /> </many-to-one>
<one-to-many class="LinkMan"/>
</set>
***
多(User) 對 多(Role)
private Set<Role>roles=new HashSet<Role>(); private Set<User>users=new HashSet<User>();
中間表只有兩個字段:user_id和role_id
<set name="roles" table="sys_user_role" cascade="save-update"> <set name="users" table="sys_user_role" inverse="true">
<key column="user_id"></key> <key column="role_id"></key>
<many-to-many class="Role" column="role_id"></many-to-many> <many-to-many class="User" column="user_id"></many-to-many>
</set> </set>
)