Hibernate 關聯映射是 ORM 核心難點。本文系統整理 7 大映射類型:多對一、一對一(主鍵/外鍵/雙向)、一對多(單向/雙向)、多對多(單向/雙向)、三種繼承策略、組合映射、復合主鍵。每類提供對象模型、映射文件、關鍵屬性解析與避坑指南,作為開發查閱速查手冊。
User { id, name, Group group }
Group { id, name }
<class name="User" table="t_user">
<id name="id"><generator class="identity"/></id>
<property name="name" column="User_name" unique="true"/>
<many-to-one name="group" column="groupid"/> // 外鍵在 User 表
</class>
Person { id, name, IdCard idCard }
IdCard { id, cardNo }
// Person 映射
<id name="id">
<generator class="foreign"><param name="property">idCard</param></generator>
</id>
<one-to-one name="idCard" constrained="true"/> // constrained=true 級聯保存/刪除
雙向:IdCard 端添加 <one-to-one name="person"/>,默認按主鍵加載。
Person { id, name, IdCard idCard }
IdCard { id, cardNo }
// Person 映射
<many-to-one name="idCard" class="IdCard" column="idcard_id" unique="true"/> // 實質是多對一+唯一約束
雙向:IdCard 端需指定 property-ref 指向關聯屬性:
<one-to-one name="person" property-ref="idCard"/> // 告訴 Hibernate 按 idCard 列加載 Person
Class { id, name, Set students }
Student { id, name }
// Class 映射
<set name="students">
<key column="classid"/> // 外鍵在 Student 表
<one-to-many class="Student"/>
</set>
缺陷:Student 端不維護關係,保存時需先 save 學生再 save 班級,且會額外發 UPDATE 更新外鍵。
// Class 端
<set name="students" inverse="true"> // 關係由多端維護
<key column="classid"/>
<one-to-many class="Student"/>
</set>
// Student 端
<many-to-one name="clazz" column="classid"/>
優勢:inverse="true" 移交關係維護權給多端,避免多餘 UPDATE,保存順序:先班級後學生。
User { id, name, Set roles }
Role { id, name }
// User 映射
<set name="roles" table="t_user_role">
<key column="userid"/>
<many-to-many class="Role" column="roleid"/>
</set>
// Role 端
<set name="users" table="t_user_role">
<key column="roleid"/> // 注意:這裡 key 是角色 ID
<many-to-many class="User" column="userid"/>
</set>
雙向時兩端 table 必須一致,key/column 互為鏡像。
| 策略 | 表結構 | 優點 | 缺點 | 映射關鍵 |
|---|---|---|---|---|
單表 (<subclass>) | 一張表含所有字段 + discriminator 區分類型 | 查詢最快,無連接 | 字段稀疏,子類字段不能非空 | discriminator-value 指定類型標識 |
連表 (<joined-subclass>) | 父表 + 子表各自表,主鍵關聯 | 規範化,支持非空約束 | 查詢需連接,性能稍弱 | table 指定子表,<key column="pid"/> 關聯列 |
聯表 (<union-subclass>) | 每個具體類一張獨立表,含所有繼承字段 | 查詢快,無連接,支持非空 | 修改父類字段需改多表,主鍵生成策略受限 | 無 discriminator,各表獨立 |
<class name="Animal" table="t_animal">
<id name="id"><generator class="native"/></id>
<discriminator column="type" type="string"/>
<property name="name"/> <property name="sex"/>
<subclass name="Pig" discriminator-value="P"><property name="weight"/></subclass>
<subclass name="Bird" discriminator-value="B"><property name="height"/></subclass>
</class>
Component 無 OID,非獨立實體,生命周期綁定宿主實體。
User { id, name, Contact contact }
Contact { email, address, zipcode, contactTel } // 無 id
// 映射
<component name="contact">
<property name="email"/>
<property name="address"/>
<property name="zipcode"/>
<property name="contactTel"/>
</component>
同一 Contact 類可在多實體中復用(User、Employee 等)。
將復合鍵屬性封裝為單獨類,必須:
Serializableequals() 和 hashCode()// SC 實體:學生-課程關係,主鍵 (sno, cno)
<class name="SC" table="t_sc">
<composite-id name="scpk" class="SCPK">
<key-property name="sno"/>
<key-property name="cno"/>
</composite-id>
<property name="sname"/> <property name="cname"/>
</class>
| 屬性 | 作用 | 常用值 |
|---|---|---|
inverse | 關係維護權移交 | true(一對多雙向/多對多雙向) |
cascade | 級聯操作 | save-update, delete, all, delete-orphan |
lazy | 延遲加載 | true/false/extra/proxy |
fetch | 抓取策略 | select, join, subselect |
constrained | 一對一主鍵關聯級聯 | true(外鍵約束+級聯) |
property-ref | 指定關聯屬性 | 一對一外鍵雙向必需 |