@ManyToOne 定義在「多」的一方實體類中,**對應表中生成外鍵列**。
@OneToMany 定義在「一」的一方實體類中,**不生成外鍵列**,僅建立對象圖導航關係。
// Programmer.java (多的一方)
@Entity
@Table(name = "t_programmer")
public class Programmer {
@Id @GeneratedValue
private Long id;
private String name;
@ManyToOne(fetch = FetchType.LAZY) // 默認 EAGER,建議 LAZY
@JoinColumn(name = "manager_id") // 指定外鍵列名,默認 manager_id
private Manager manager;
// getter/setter
}
// Manager.java (一的一方)
@Entity
@Table(name = "t_manager")
public class Manager {
@Id @GeneratedValue
private Long id;
private String name;
// 無 @OneToMany,單向關聯
}
生成 DDL:t_programmer 表包含 manager_id BIGINT 外鍵引用 t_manager.id。
// Manager.java
@OneToMany(mappedBy = "manager", cascade = CascadeType.ALL, orphanRemoval = true)
private Set programmers = new HashSet<>();
// Programmer.java 保持不變 (已有 @ManyToOne @JoinColumn)
// 注意:mappedBy = "manager" 指向 Programmer 中的屬性名,告訴 Hibernate「關係由那邊維護」
Programmer.manager) 維护,**不再生成中間表或額外外鍵**。Set 避免重複,**必須正確實現 equals/hashCode (基於業務鍵或 ID+版本號)**,否則實體脫管/合併時出現異常。// Manager.java
@OneToMany
@JoinColumn(name = "manager_id") // 錯誤!這會在 t_programmer 再建一個外鍵或報錯
private Set programmers;
// Programmer.java
@ManyToOne
@JoinColumn(name = "manager_id") // 也維護同一列
private Manager manager;
後果:Hibernate 嘗試雙向更新同一外鍵列,產生多餘 UPDATE、死鎖或異常 Multiple representations of same entity。
// Manager.java
@OneToMany
@JoinColumn(name = "manager_id") // 在「一」的一方維護外鍵
private List programmers;
// Programmer.java 無任何關聯註解
缺點:Hibernate 需額外 UPDATE 設置外鍵 (先 INSERT Programmer, 再 UPDATE manager_id);無法在 Programmer 端導航到 Manager;List 需 @OrderColumn 維護順序。**不如雙向或單向 @ManyToOne 自然。**
fetch = FetchType.LAZY**,否則查一個 Programmer 連帶加載 Manager 甚至遞歸加載整個對象圖,導致 N+1 或 StackOverflow。email) 或「ID + 版本號」或僅比較實例引用 (僅用於新建實體)。@JsonIgnore / @JsonManagedReference / @JsonBackReference (Jackson) 或 DTO 轉換層隔離。hibernate.hbm2ddl.auto=update 僅供開發,**生產必須用 Flyway/Liquibase 管理遷移腳本**。@OneToMany(mappedBy=...) 形成雙向。