首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Hibernate 關聯映射全景指南:從多對一、一對多到多對多的 XML 與註解雙實戰

     編輯:Java 綜合教學

ORM 核心思想:對象圖與關係表的橋樑

Hibernate 通過映射元數據 (XML 或註解),將 Java 對象圖中的引用關係轉換為數據庫外鍵關係,實現 操作對象即操作數據。

一、多對一單向關聯 (N:1)

場景:員工屬於一部門,員工實體持有部門引用。

XML 映射

<class name="Employee" table="employee">
  <id name="id"><generator class="native"/></id>
  <property name="name"/>
  <many-to-one name="dept" column="dept_id" class="Dept"/>
</class>
  • name="dept":實體屬性名
  • column="dept_id":員工表外鍵列
  • class="Dept":目標實體全限定名

註解映射

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "dept_id")
private Dept dept;

二、雙向一對多關聯 (1:N)

在多對一基礎上,部門端持有員工集合。

部門端映射 (集合端)

<set name="employees" inverse="true" cascade="save-update">
  <key column="dept_id"/>
  <one-to-many class="Employee"/>
</set>
  • inverse="true":集合端不維護關係,由多對一端 (員工) 維護外鍵,避免雙向各執行一次 UPDATE。
  • cascade="save-update":保存部門時級聯保存員工。

註解映射

// Employee 端 (關係維護端)
@ManyToOne
@JoinColumn(name = "dept_id")
private Dept dept;

// Dept 端 (集合端)
@OneToMany(mappedBy = "dept", cascade = CascadeType.ALL, orphanRemoval = true)
private Set employees = new HashSet<>();

三、單向多對多關聯 (M:N)

場景:員工參與多項目,項目不需知員工。中間表 emp_project。

XML 映射

<set name="projects" table="emp_project">
  <key column="emp_id"/>
  <many-to-many class="Project" column="pro_id"/>
</set>

註解映射

@ManyToMany
@JoinTable(
    name = "emp_project",
    joinColumns = @JoinColumn(name = "emp_id"),
    inverseJoinColumns = @JoinColumn(name = "pro_id")
)
private Set projects = new HashSet<>();

四、雙向多對多關聯

員工、項目雙向持有集合,任選一方為維護端。

XML 映射 (項目為維護端)

<!-- Employee.hbm.xml 非維護端 -->
<set name="projects" table="emp_project" inverse="true">
  <key column="emp_id"/>
  <many-to-many class="Project" column="pro_id"/>
</set>

<!-- Project.hbm.xml 維護端 -->
<set name="employees" table="emp_project" cascade="save-update">
  <key column="pro_id"/>
  <many-to-many class="Employee" column="emp_id"/>
</set>

註解映射

// Employee 非維護端
@ManyToMany(mappedBy = "employees")
private Set projects = new HashSet<>();

// Project 維護端
@ManyToMany
@JoinTable(
    name = "emp_project",
    joinColumns = @JoinColumn(name = "pro_id"),
    inverseJoinColumns = @JoinColumn(name = "emp_id")
)
private Set employees = new HashSet<>();

五、集合類型選擇:Set vs List vs Bag

類型特點適用場景Hibernate 映射
Set無序、唯一、高性能去重多對多、一對多 (默認首選)<set>
List有序、可重複、需索引列順序敏感業務 (如步驟、評論)<list> + <index>
Bag無序、可重複、無索引極少用,僅兼容舊代碼<bag>

建議: 90% 場景用 Set,避免重複元素導致的主鍵衝突與性能損耗。

六、關鍵屬性速查表

屬性作用典型值注意
inverse聲明非關係維護端true/false雙向關聯必須一方為 true
cascade級聯操作範圍save-update, delete, all, all-delete-orphan謹慎用 delete-orphan,防誤刪
fetch加載策略select, join, subselect, batch集合默認 LAZY,單端可 EAGER
batch-size批量抓取大小10-25優化 N+1 問題利器
orphanRemoval移除集合元素時刪除實體true/false僅適用 @OneToMany/mappedBy 端

七、常見坑點與解決方案

  1. 雙向關聯雙邊維護導致中間表重複 INSERT: 一邊設置 inverse="true" / mappedBy。
  2. 懶加載異常 LazyInitializationException: Session 關閉後訪問集合。解決:DTO 投影、Hibernate.initialize()、Open Session In View (慎用)。
  3. 級聯刪除誤刪關聯對象: cascade="delete" 會刪除被引用對象。多對多禁用 delete 級聯,僅用 save-update。
  4. 中間表列名衝突: 顯式指定 joinColumns/inverseJoinColumns 或 key column/many-to-many column。
  5. 集合用 List 缺少索引列: 映射添加 <list-index> 或 @OrderColumn。

總結

Hibernate 關聯映射的核心在於 明確關係維護端 (inverse/mappedBy) 與 精準控制級聯範圍 (cascade/orphanRemoval)。掌握 many-to-one/one-to-many/many-to-many 三大基礎映射及其雙向組合,配合 Set 集合與顯式列名,即可應對 95% 關聯場景。註解映射與 XML 映射一一對應,團隊可根據習慣統一風格,核心原理不變。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved