使用 Spring 一段時間後,決定深入學習 JPA(Java Persistence API)。本文記錄從 ORM 基礎概念到 JPA 實體定義、屬性映射、四大關聯關係、單向/雙向導航的完整學習筆記,並附上可直接運行的程式碼範例。
ORM (Object/Relational Mapping) 解決物件導向模型與關係型資料庫範式不匹配的問題。透過元數據描述映射關係,將物件自動持久化到資料庫,本質是資料形式轉換。雖引入額外開銷,但極大提升開發效率與可維護性。
主流 ORM 框架具備四大核心功能:映射元數據、CRUD API、物件查詢語言(JPQL/HQL)、物件圖導航獲取資料。
EntityManager 統一管理實體生命週期。persistence.xml 或 Spring Data JPA 自動配置,零侵入式整合。@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username; // 欄位名同屬性名,無需 @Column
@Column(name = "passwd") // 資料庫欄位名不同,需指定
private String password;
@Transient // 不映射到資料庫
private String others;
}
關鍵註解:
@Entity:標記為持久化實體,對應一張表。@Table:指定表名、Schema、唯一約束等。@Id + @GeneratedValue:主鍵生成策略(IDENTITY/SEQUENCE/AUTO/TABLE)。@Column:自訂欄位名、長度、可空、唯一等。@Transient:忽略該屬性,不持久化。| 類型 | 註解 | 外鍵位置 | 典型場景 |
|---|---|---|---|
| 一對一 | @OneToOne + @JoinColumn | 任一端(通常主表) | 用戶-身份證、訂單-付款 |
| 多對一 | @ManyToOne + @JoinColumn | 多方(員工表) | 員工-公司、訂單-用戶 |
| 一對多 | @OneToMany + @JoinColumn 或 mappedBy | 多方(書籍表) | 學生-書籍、部門-員工 |
| 多對多 | @ManyToMany + @JoinTable | 中間表 | 學生-課程、產品-目錄 |
@Entity
public class Product {
@Id @GeneratedValue private Long id;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "product_catalog",
joinColumns = @JoinColumn(name = "product_id"),
inverseJoinColumns = @JoinColumn(name = "catalog_id"))
private Set catalogs = new HashSet<>();
}
@Entity
public class Catalog {
@Id @GeneratedValue private Long id;
// 雙向導航可在這裡加 @ManyToMany(mappedBy = "catalogs")
}
中間表 product_catalog 包含兩外鍵組成聯合主鍵,JPA 自動維護。
User → Address)。mappedBy 指向「主動端」屬性名,由主動端維護外鍵,被動端僅作鏡像查詢,不影響資料庫結構。// 主動端 @OneToOne @JoinColumn(name = "address_id") private Address address; // 被動端(雙向) @OneToOne(mappedBy = "address") private User user;
LAZY 載入(@OneToMany/@ManyToMany 預設即為 LAZY),避免 N+1 問題配合 EntityGraph 或 JOIN FETCH 精確載入。addXxx/removeXxx 方法。cascade 謹慎使用,REMOVE 可能誤刪關聯端資料,優先手動控制。equals/hashCode 基於業務主鍵(非資料庫 ID)。後續將介紹 JPA 配置(persistence.xml/Spring Data JPA)、Repository 使用、JPQL/QueryDSL 查詢、事務管理與效能調優。