鐵人賽一乍眼過半啦!
隨著資料庫技術的發展,Entity 間的關聯在資料模型中佔有重要的位置。在開發時,我們經常遇到如何模擬現實世界中各種複雜的關係。在
今天來談談 Spring Data JPA 中最常用的兩種關聯:One-to-One 和 Many-to-One。
如字面上所述,就是一個實體與另一個實體間有著一對一的關聯。
範例:
假設我們要開發一個員工資料系統。每位員工都有一張員工證。在這裡,員工和員工證間就形成了一個 One-to-One 的關聯。
@Entity
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne(mappedBy = "employee", cascade = CascadeType.ALL)
private WorkCard workCard;
}
@Entity
public class WorkCard {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne
@JoinColumn(name = "employee_id")
private Employee employee;
}
我們透過
@OneToOne
註解建立了Employee
和WorkCard
之間的一對一關聯。
Many-to-One 的概念則是多個 Entity 可以對應到同一個 Entity。
假設我們還是在開發員工資料系統,這次要添加部門概念。一個部門可以有多位員工,但每位員工只隸屬於一個部門。這邊員工和部門間就形成了一個 Many-to-One 的關聯。
@Entity
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy = "department")
private List<Employee> employees;
}
@Entity
public class Employee {
// ... 其他屬性
@ManyToOne
@JoinColumn(name = "department_id")
private Department department;
}
利用
@ManyToOne
註解表示每位員工只屬於一個部門。而部門則用@OneToMany
表示一個部門可以有多位員工。
雙向關聯中的「主控方」問題
在雙向關聯中,我們需要確定哪一邊是主控方 (owning side
),錯誤設定主控方會導致資料不一致。
一般來說,我們會將具有 FK 的那一邊設為主控方。在上述的例子中,WorkCard
包含一個指向 Employee
的外鍵,所以它是主控方。
N+1 查詢問題
從部門中取得員工時,可能會遇到 N+1 查詢問題。如果我們有 N 個部門,可能會發出 N+1 次的查詢。
→ 使用 JPA 的 JOIN FETCH
或 Hibernate 的 BatchSize
註解可以有效解決這個問題。
延遲加載與即時加載
在 JPA 中,我們可以選擇使用延遲加載 (LAZY) 或即時加載 (EAGER)。選擇不當可能導致效能問題或 LazyInitializationException
。
→ 對於大多數的關聯,使用延遲加載是比較好的選擇。只有當確定每次都需要使用關聯資料時,才考慮使用即時加載。
@OneToOne
註解。FetchType.EAGER
,因為它可能導致效能問題。透過今天的文章,可以大致了解 One-to-One 和 Many-to-One 這兩種關聯的基礎使用方法。在實際開發中,當然還有很多細節和問題(坑 XD)等著我們解決,在接下來的兩天中會繼續探討其他關聯方式~