Hibernate 通過映射元數據 (XML 或註解),將 Java 對象圖中的引用關係轉換為數據庫外鍵關係,實現 操作對象即操作數據。
場景:員工屬於一部門,員工實體持有部門引用。
<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;
在多對一基礎上,部門端持有員工集合。
<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 Setemployees = new HashSet<>();
場景:員工參與多項目,項目不需知員工。中間表 emp_project。
<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<>();
員工、項目雙向持有集合,任選一方為維護端。
<!-- 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 Setprojects = new HashSet<>(); // Project 維護端 @ManyToMany @JoinTable( name = "emp_project", joinColumns = @JoinColumn(name = "pro_id"), inverseJoinColumns = @JoinColumn(name = "emp_id") ) private Set employees = new HashSet<>();
| 類型 | 特點 | 適用場景 | 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 端 |
inverse="true" / mappedBy。LazyInitializationException: Session 關閉後訪問集合。解決:DTO 投影、Hibernate.initialize()、Open Session In View (慎用)。cascade="delete" 會刪除被引用對象。多對多禁用 delete 級聯,僅用 save-update。joinColumns/inverseJoinColumns 或 key column/many-to-many column。List 缺少索引列: 映射添加 <list-index> 或 @OrderColumn。Hibernate 關聯映射的核心在於 明確關係維護端 (inverse/mappedBy) 與 精準控制級聯範圍 (cascade/orphanRemoval)。掌握 many-to-one/one-to-many/many-to-many 三大基礎映射及其雙向組合,配合 Set 集合與顯式列名,即可應對 95% 關聯場景。註解映射與 XML 映射一一對應,團隊可根據習慣統一風格,核心原理不變。