中間表、關聯表常無單列主鍵,需組合多列為聯合主鍵。Hibernate/JPA 提供三種映射方式,核心要求:**主鍵類必須實現 Serializable、重寫 equals/hashCode**。
@Embeddable
public class OrderItemKey implements Serializable {
private Long orderId;
private Long productId;
// 無參構造、getter/setter、equals/hashCode 必須完整實現
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof OrderItemKey)) return false;
OrderItemKey that = (OrderItemKey) o;
return Objects.equals(orderId, that.orderId) && Objects.equals(productId, that.productId);
}
@Override
public int hashCode() { return Objects.hash(orderId, productId); }
}
@Entity
@Table(name = "order_item")
public class OrderItem {
@Id
private OrderItemKey id; // 組合主鍵作為單一字段
private int quantity;
private BigDecimal price;
// getter/setter
}
優點:主鍵封裝性好,實體類乾淨;缺點:查詢時需構造 Key 對象(em.find(OrderItem.class, new OrderItemKey(1L, 2L)))。
public class OrderItemKey implements Serializable {
private Long orderId;
private Long productId;
// equals/hashCode/getter/setter
}
@Entity
public class OrderItem {
@EmbeddedId
private OrderItemKey id; // 直接嵌入
private int quantity;
}
與方式一幾乎等價,@EmbeddedId 語義更明確:「這是一個嵌入式主鍵」。
public class OrderItemKey implements Serializable {
private Long orderId;
private Long productId;
// equals/hashCode/getter/setter
}
@Entity
@IdClass(OrderItemKey.class) // 指定主鍵類
public class OrderItem {
@Id
private Long orderId; // 主鍵字段直接在實體中
@Id
private Long productId;
private int quantity;
}
優點:字段平鋪,JPQL 查詢直接用 WHERE o.orderId = :oid,無需攜帶 Key 對象;缺點:實體類字段冗余,主鍵類與實體類字段需**名稱、類型完全一致**。
| 維度 | @Embeddable + @Id | @EmbeddedId | @IdClass |
|---|---|---|---|
| 主鍵類注解 | @Embeddable | 無需(建議加) | 無需 |
| 實體類字段 | 單一 Key 字段 | 單一 Key 字段 | 多個 @Id 字段平鋪 |
| 查詢/查找方式 | em.find(Entity, Key) | em.find(Entity, Key) | em.find(Entity, Key) 或單獨字段 |
| JPQL 友好度 | 需 join/key 訪問 | 同左 | 直接訪問字段,最友好 |
| 遷移舊代碼 | 適合新設計 | 適合新設計 | 適合從 Hibernate XML 遷移 |
| 推薦場景 | 領域驅動設計、值對象建模 | 同上,語義更強 | 傳統 DAO、大量 JPQL 查詢 |
Serializable,否則分布式環境/二級緩存會報錯。@Id 字段一致。public static class 內部類或獨立類,便於管理。三種方式各有優勢,**新項目推薦 @EmbeddedId**(語義最清晰、封裝性最好);**大量 JPQL 查詢的傳統項目用 @IdClass**;避免混用。牢記:主鍵類 = Serializable + equals/hashCode + 字段一致性,這是聯合主鍵映射的鐵律。