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

Hibernate 一對多雙向關聯完整實作:實體、映射、級聯與測試

     編輯:Java 程式設計入門

一對多雙向關聯是 Hibernate 中最常見的關聯模型(如:客戶-訂單、部門-員工)。本文以「客戶-訂單」為例,完整展示實體類別設計、.hbm.xml 映射配置、雙向關聯維護、級聯操作策略,以及測試程式碼,幫助您避開「多方維護外鍵、單方 inverse=true、級聯刪除誤傷」等經典坑點。

一、領域模型與資料庫結構

  • Customer(單方/一的一方):c_id (PK)、c_name、bank、phone
  • Orders(多方/多的一方):c_id (PK)、order_no、money、customer_id (FK → Customer.c_id)
  • 關聯邏輯:一個客戶擁有多筆訂單;訂單屬於單一客戶。

二、實體類別(POJO)


// Customer.java
package com.example.model;

import java.util.HashSet;
import java.util.Set;

public class Customer {
    private String id;
    private String cName;
    private String bank;
    private String phone;
    private Set orders = new HashSet<>(); // 集合型別用 Set 避免重複

    // Getter/Setter 略...
    public Set getOrders() { return orders; }
    public void setOrders(Set orders) { this.orders = orders; }

    // 便利方法:雙向關聯同步
    public void addOrder(Order order) {
        orders.add(order);
        order.setCustomer(this);
    }
    public void removeOrder(Order order) {
        orders.remove(order);
        order.setCustomer(null);
    }
}

// Order.java
package com.example.model;

public class Order {
    private String id;
    private String orderNo;
    private Double money;
    private Customer customer; // 多方持有單方引用

    // Getter/Setter 略...
}

三、映射檔配置(.hbm.xml)

1. Customer.hbm.xml(單方,配置 one-to-many)

<?xml version="1.0" encoding="UTF-8"?>
<hibernate-mapping>
    <class name="com.example.model.Customer" table="CUSTOMER">
        <id name="id" column="C_ID" length="32">
            <generator class="uuid.hex"/>
        </id>
        <property name="cName" column="CNAME" length="100"/>
        <property name="bank" column="BANK" length="100"/>
        <property name="phone" column="PHONE" length="20"/>

        <!-- 一對多雙向:單方配置 inverse=true,放棄外鍵維護權 -->
        <set name="orders" cascade="all" inverse="true" lazy="false">
            <key column="CUSTOMER_ID"/>
            <one-to-many class="com.example.model.Order"/>
        </set>
    </class>
</hibernate-mapping>

2. Order.hbm.xml(多方,配置 many-to-one)

<?xml version="1.0" encoding="UTF-8"?>
<hibernate-mapping>
    <class name="com.example.model.Order" table="ORDERS">
        <id name="id" column="C_ID" length="32">
            <generator class="uuid.hex"/>
        </id>
        <property name="orderNo" column="ORDERNO" length="17"/>
        <property name="money" column="MONEY" type="double"/>

        <!-- 多方維護外鍵,不設 inverse -->
        <many-to-one name="customer" class="com.example.model.Customer"
                     column="CUSTOMER_ID" cascade="all" lazy="false" not-null="true"/>
    </class>
</hibernate-mapping>

四、關鍵配置解析

屬性放置位置含義建議值
inverse單方 <set>關聯維護權反轉:true 表示「由多方負責更新外鍵」true(單方必須設)
cascade雙方均可級聯操作傳播:all / save-update / delete / none單方 all,多方視業務而定
not-null多方 <many-to-one>外鍵欄位不可為空,確保訂單必須屬於某客戶true
lazy集合/多對一延遲載入開關測試期 false,生產 true(預設)

五、測試程式碼:正確建立雙向關聯

@Test
public void testSaveCustomerWithOrders() {
    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction();

    Customer customer = new Customer();
    customer.setCName("清華大學出版社");
    customer.setBank("9559501012356789");
    customer.setPhone("010-62772015");

    Order order = new Order();
    order.setOrderNo(String.valueOf(System.currentTimeMillis()));
    order.setMoney(1234.56);

    // 關鍵:雙向關聯雙邊都要 set
    customer.addOrder(order); // 內部同時執行 order.setCustomer(customer)

    session.save(customer); // 因 cascade="all",order 會自動持久化
    tx.commit();
    session.close();

    System.out.println("客戶 ID:" + customer.getId());
}

六、常見錯誤與修正

  1. 只單邊 set:customer.getOrders().add(order) 卻忘記 order.setCustomer(customer) → 外鍵為 NULL,拋 PropertyValueException(因 not-null="true")。
    ✅ 修正:在實體提供 addOrder() 便利方法,一次搞定雙邊。
  2. 單方未設 inverse=true:Hibernate 會發出兩條 UPDATE 外鍵 SQL,效能損耗且可能死鎖。
    ✅ 修正:單方 <set> 必加 inverse="true"。
  3. 級聯刪除誤傷:cascade="delete" 或 all 刪除客戶時會連帶刪除所有訂單。
    ✅ 修正:若訂單需保留歷史,單方改 cascade="save-update",手動處理刪除邏輯。
  4. Set 需正確實作 equals/hashCode:若未覆寫,預設用記憶體位址比較,導致集合操作異常。
    ✅ 修正:實體類別務必依業務主鍵實作 equals/hashCode。

七、註解式配置對照(JPA / Hibernate Annotations)

// Customer
@OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set orders = new HashSet<>();

// Order
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "CUSTOMER_ID", nullable = false)
private Customer customer;

mappedBy 等同於 XML 的 inverse="true",指明由多方 Order.customer 維護關聯。

八、總結

Hibernate 一對多雙向關聯的核心口訣:「多方維護外鍵、單方 inverse=true、雙邊同步 set、級聯按需配」。掌握這四點,配合便利方法封裝雙向綁定邏輯,即可在複雜業務中穩健操作關聯物件圖。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved