首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

EJB 3 開發指南(8):一對多雙向關聯與關聯表映射

     編輯:Java 相關知識

一對多是最常見的關聯類型。EJB 3 提供 @OneToMany(多方)與 @ManyToOne(單方)雙向映射,支援外鍵直連與關聯表兩種模式。本文以 Customer(客戶)與 Order(訂單)為例,完整示範兩種映射方式。

一、資料表結構

t_customers

id (PK) | name | ...

t_orders (外鍵模式)

id (PK) | product_id | count | customer_id (FK → t_customers.id)

t_orders 表結構

二、外鍵直連模式 (最常用)

Customer 類別(一端,關聯維護端)

@Entity
@Table(name = "t_customers")
public class Customer {
    private int id;
    private String name;
    private Referee referee;
    private Collection<Order> orders;

    @OneToMany(mappedBy = "customer", cascade = CascadeType.ALL)
    public Collection<Order> getOrders() { return orders; }
    public void setOrders(Collection<Order> orders) { this.orders = orders; }
    // ... 其他 getter/setter
}

Order 類別(多端,擁有外鍵)

@Entity
@Table(name = "t_orders")
public class Order {
    private int id;
    private String productId;
    private int count;
    private Customer customer;

    @ManyToOne
    @JoinColumn(name = "customer_id")  // 指定外鍵欄位
    public Customer getCustomer() { return customer; }
    public void setCustomer(Customer customer) { this.customer = customer; }
    // ... 其他 getter/setter
}

關鍵點

  • mappedBy="customer":指向 Order 端的關聯屬性名,表示由 Order 維護外鍵
  • @JoinColumn(name="customer_id"):指定 t_orders 表的外鍵欄位名
  • cascade=ALL:持久化 Customer 時級聯持久化/更新/刪除所有 Order

三、測試程式碼:外鍵模式

Customer customer = new Customer();
customer.setName("微軟");

List<Order> orders = new ArrayList<Order>();

Order order1 = new Order();
order1.setProductId("1234");
order1.setCount(20);
order1.setCustomer(customer);  // 設定反向關聯
orders.add(order1);

Order order2 = new Order();
order2.setProductId("4321");
order2.setCount(12);
order2.setCustomer(customer);
orders.add(order2);

customer.setOrders(orders);
em.persist(customer);  -- 級聯持久化 2 筆訂單

四、關聯表模式 (無外鍵欄位)

資料表結構

t_orders 表移除 customer_id 欄位,新增關聯表:

t_customers_orders

t_customers_id (FK) | orders_id (FK)

t_customers_orders 關聯表結構

Customer 類別修改

@OneToMany
@JoinTable(
    name = "t_customers_orders",
    joinColumns = @JoinColumn(name = "t_customers_id", referencedColumnName = "id"),
    inverseJoinColumns = @JoinColumn(name = "orders_id", referencedColumnName = "id")
)
public Collection<Order> getOrders() { return orders; }

Order 類別修改

移除 customer 屬性及其 getter/setter(不再需要反向導航)。

持久化順序要求


// 必須先持久化 Order,再持久化 Customer
em.persist(order1);
em.persist(order2);
customer.setOrders(orders);
em.persist(customer);

因為關聯表需雙方 ID 才能建立記錄,Order 必須先有 ID。

五、兩種模式對比

維度外鍵模式關聯表模式
資料表結構多端表有 FK 欄位需額外關聯表
導航方向雙向 (mappedBy)單向 (Customer→Order)
持久化順序任意 (有 cascade)必須先存多端
適用場景標準主從關係多對多退化、歷史系統無 FK、需關聯表掛載屬性
刪除行為Cascade.REMOVE 可級聯刪除需手動清理關聯表或資料庫 CASCADE

六、最佳實踐建議

  • 優先使用外鍵模式:語義清晰、資料庫層級約束、雙向導航方便
  • 集合型別用 List 而非 Collection:保持順序、支援 @OrderColumn 排序
  • 避免 CascadeType.REMOVE 濫用:刪除客戶時自動刪除所有訂單風險極大,建議軟刪除或業務邏輯控制
  • 延遲載入陷阱:Session 關閉後存取 customer.getOrders() 會拋 LazyInitializationException,使用 FETCH JOIN 或 DTO 轉換
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved