Hibernate 支援將 Java 集合類型映射為資料庫關聯關係,主要分類:
| 集合介面 | 特性 | 資料庫表現 | 適用場景 |
|---|---|---|---|
| List | 有序、可重複 | 索引欄位 (list_index) | 順序重要的集合 |
| Set | 無序、不可重複 | 無索引,靠主鍵/唯一約束 | 唯一性關聯 |
| Map | 鍵值對、鍵唯一 | 鍵欄位 (map_key) | 鍵值關聯查詢 |
| Bag | 無序、可重複 | 無索引,允許重複行 | 效能最佳(無序) |
| Array | 固定長度、有序 | 索引欄位 | 陣列屬性映射 |
@Entity
public class Department {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany
@JoinColumn(name = "dept_id") // 外鍵在 Employee 表
private List employees = new ArrayList<>();
// getter/setter
}
@Entity
public class Employee {
@Id @GeneratedValue
private Long id;
private String name;
// 無反向關聯
}
<class name="Department" table="DEPARTMENT">
<id name="id" column="DEPT_ID">
<generator class="native"/>
</id>
<property name="name" column="DEPT_NAME"/>
<list name="employees" table="EMPLOYEE">
<key column="DEPT_ID"/>
<list-index column="EMP_IDX"/>
<one-to-many class="Employee"/>
</list>
</class>
@Entity
public class Department {
@OneToMany(mappedBy = "department", cascade = CascadeType.ALL)
private Set employees = new HashSet<>();
}
@Entity
public class Employee {
@ManyToOne
@JoinColumn(name = "DEPT_ID")
private Department department;
}
關鍵點:mappedBy 指定關係擁有方,cascade 定義級聯操作。
@OrderColumn(name = "DISPLAY_ORDER") // JPA 2.0 private Listtasks;
或 XML:<list-index column="DISPLAY_ORDER"/>
@Entity
public class Student {
@ElementCollection
@CollectionTable(name = "STUDENT_SCORES", joinColumns = @JoinColumn(name = "STUDENT_ID"))
@MapKeyColumn(name = "SUBJECT")
@Column(name = "SCORE")
private Map scores = new HashMap<>();
}
@OneToMany(mappedBy = "order")
@OrderBy("id") // 僅查詢排序,不維護索引
private Collection items = new ArrayList<>(); // 宣告為 Collection
| 類型 | 註解 | 資料表 |
|---|---|---|
| 基本型別/字串 | @ElementCollection | 單獨集合表 |
| 嵌入物件 | @ElementCollection + @Embeddable | 單獨集合表 |
| 實體關聯 | @OneToMany / @ManyToMany | 實體表 + 關聯表 |
| 問題 | 原因 | 解決方案 |
|---|---|---|
| N+1 查詢 | 集合預設 LAZY 載入 | FetchType.EAGER / join fetch / @BatchSize |
| 重複資料 | Bag 允許重複 + join fetch | 改用 Set 或 distinct 查詢 |
| 索引維護開銷 | List/Array 更新索引 | 改用 Bag/Set 或 @OrderBy |
| 孤兒刪除 | 移除集合元素未刪除實體 | orphanRemoval=true + cascade=ALL |
<list name="items"> <key column="PARENT_ID"/> <list-index column="IDX"/> <one-to-many class="Child"/> </list> <set name="items"> <key column="PARENT_ID"/> <one-to-many class="Child"/> </set--> <map name="items"> <key column="PARENT_ID"/> <map-key column="MAP_KEY"/> <one-to-many class="Child"/> </map--> <bag name="items"> <key column="PARENT_ID"/> <one-to-many class="Child"/> </bag-->