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

Hibernate 一對一關聯映射詳解:主鍵關聯與唯一外鍵關聯

     編輯:Java 程式設計入門

核心概念

Hibernate 中一對一關聯分為兩種實現方式:

  1. 主鍵關聯:雙方共享同一主鍵值,被控方主鍵同時是外鍵指向主控方。<one-to-one constrained="true"> + <generator class="foreign">。
  2. 唯一外鍵關聯:雙方各有主鍵,主控方表中有一個唯一外鍵列指向被控方。<many-to-one unique="true"> 或 <one-to-one property-ref="...">。

場景一:主鍵關聯(雙向)完整映射

業務場景:Person (主控) 1:1 Address (被控)。Person 表主鍵 id,Address 表主鍵 id 同時作為外鍵指向 Person。

實體類

// 主控方 Person
public class Person {
    private Long id;
    private String username;
    private Address address; // 關聯對象
    // Getter/Setter...
}

// 被控方 Address
public class Address {
    private Long id; // 共享主鍵
    private String addressName;
    private Person person; // 反向引用
    // Getter/Setter, equals/hashCode...
}

映射文件 (.hbm.xml)

<!-- Person 映射 -->
<class name="Person" table="person">
    <id name="id" column="id" type="long">
        <generator class="native"/> <!-- 主控方自主生成主鍵 -->
    </id>
    <property name="username" column="username" type="string"/>
    <one-to-one name="address" class="Address" cascade="all" constrained="false"/>
</class>

<!-- Address 映射 -->
<class name="Address" table="address">
    <id name="id" column="id" type="long">
        <generator class="foreign"> <!-- 關鍵:外鍵生成器 -->
            <param name="property">person</param> <!-- 指向關聯屬性 -->
        </generator>
    </id>
    <one-to-one name="person" class="Person" constrained="true"/> <!-- constrained=true 表明此表外鍵約束指向 Person -->
    <property name="addressName" column="address_name" type="string"/>
</class>

關鍵點解析

  • constrained="false" (Person 端) / "true" (Address 端):只能有一端為 true,表示該端表具有外鍵約束。Address 表主鍵同時是指向 Person 的外鍵,故 Address 端 true。
  • generator class="foreign":保存 Address 時,Hibernate 讀取關聯的 Person.id 作為 Address.id,實現主鍵共享。
  • cascade="all":Person 保存/刪除時級聯操作 Address。
  • 雙向維護:代碼中設置關聯時需雙向賦值:person.setAddress(addr); addr.setPerson(person);。

場景二:唯一外鍵關聯(單向/雙向)

業務場景:User 1:1 Profile。User 表有 profile_id 列,UNIQUE 約束指向 Profile 表主鍵。

映射片段

<class name="User" table="users">
    <id name="id" column="id"><generator class="native"/></id>
    <property name="username"/>
    <!-- 方式 A: many-to-one + unique=true (推薦) -->
    <many-to-one name="profile" class="Profile" column="profile_id" unique="true" cascade="all"/>
    
    <!-- 方式 B: one-to-one property-ref (舊版) -->
    <!-- <one-to-one name="profile" class="Profile" property-ref="user"/> -->
</class>

<class name="Profile" table="profiles">
    <id name="id" column="id"><generator class="native"/></id>
    <property name="bio"/>
    <!-- 反向引用(可選) -->
    <one-to-one name="user" class="User" property-ref="profile"/>
</class>

對比總結:選哪種?

維度主鍵關聯唯一外鍵關聯
表結構雙方共享 PK,被控方 PK 即 FK各自獨立 PK,主控方有唯一 FK 列
插入順序必須先插主控方,再插被控方順序靈活(可先插 Profile 再關聯 User)
級聯刪除自然級聯(FK 約束)需配置 cascade 或資料庫 FK ON DELETE
適用場景強生命週期綁定(如:用戶-用戶詳情、訂單-支付詳情)弱綁定、可選關聯(如:用戶-擴展配置、員工-工位)
映射複雜度較高 (foreign generator, constrained)較低 (many-to-one unique=true)

現代化註解映射 (JPA/Hibernate 5+)

// 主鍵關聯
@Entity public class Person {
    @Id @GeneratedValue Long id;
    @OneToOne(mappedBy = "person", cascade = CascadeType.ALL)
    private Address address;
}

@Entity public class Address {
    @Id Long id; // 無 @GeneratedValue
    @MapsId // 關鍵:主鍵來自關聯端
    @OneToOne @JoinColumn(name = "id")
    private Person person;
}

// 唯一外鍵關聯
@Entity public class User {
    @Id @GeneratedValue Long id;
    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "profile_id", unique = true)
    private Profile profile;
}

最佳實踐建議

  1. 優先考慮合併為單表:若 1:1 關聯極其緊密、查詢總是聯合,合併表消除 Join 開銷最簡單高效。
  2. 業務可選性:被控方可能不存在時,用唯一外鍵關聯(FK 可為 NULL),主鍵關聯不支援 NULL。
  3. 避免雙向一對一:除非業務必須從被控方導航主控方,否則單向映射更簡潔。
  4. 索引優化:唯一外鍵列必須建立 UNIQUE INDEX,資料庫層面保證 1:1 語義。

掌握兩種一對一映射本質,能根據業務強弱綁定特性做出最優表結構與映射決策。

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