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

Hibernate 3 學習筆記(十八):一對多雙向關聯與效能優化

     編輯:Java 相關知識

從多對一到一對多:反向導航

上一篇介紹了「多對一」(User → Room)。若 Room 也需要知道有哪些 User,即形成**一對多雙向關聯**。

單向一對多映射

Room.hbm.xml

<set name="users" table="user" cascade="all">
    <key column="room_id"/>
    <one-to-many class="com.hb3.pack_17.model.User"/>
</set>

此時 User.hbm.xml **無需任何映射**,User 不知道 Room 的存在。

測試:由 Room 端維護關係

Room room = new Room(); room.setAddress("NTU-M8-419");
room.setUsers(new HashSet<>());
room.addUser(new User("yangye"));
room.addUser(new User("shenbin"));
session.save(room); // cascade="all" 連帶存 User

雙向關聯:雙方都知道對方

實體類別修改

User 新增 Room room 屬性;Room 保留 Set<User> users。

映射檔雙向聲明

User.hbm.xml(多對一端):

<many-to-one name="room" column="room_id"
    class="com.hb3.pack_20.model.Room"
    cascade="save-update" outer-join="true"/>

Room.hbm.xml(一對多端):

<set name="users" table="user" cascade="save-update">
    <key column="room_id"/>
    <one-to-many class="com.hb3.pack_20.model.User"/>
</set>

效能陷阱:誰來維護關係?

錯誤示範:由「一」的一方 維護

Room room = new Room(); room.setAddress("NTU-M8-419");
room.setUsers(new HashSet<>());
room.addUser(user1); room.addUser(user2);
// User 端未 setRoom
session.save(room);

產生 SQL:

INSERT INTO room (address) VALUES (?)
INSERT INTO user (name, room_id) VALUES (?, ?)  -- room_id 為 NULL!
INSERT INTO user (name, room_id) VALUES (?, ?)  -- room_id 為 NULL!
UPDATE user SET room_id=? WHERE id=?            -- 額外 UPDATE 回填
UPDATE user SET room_id=? WHERE id=?

因 Room 存入時尚未生成 ID,User 先存 room_id 為 NULL,事後再 UPDATE。**多出 2N 條 UPDATE**。

正確做法:將控制權交給「多」的一方

在 Room.hbm.xml 的 <set> 加上 inverse="true":

<set name="users" table="user" cascade="save-update" inverse="true"> ... </set>

並由 User 端 設定關聯:

User user1 = new User("bush");
User user2 = new User("caterpillar");
Room room = new Room("NTU-M8-419");
room.setUsers(new HashSet<>());
room.addUser(user1); room.addUser(user2);

// 關鍵:多方必須認識單方
user1.setRoom(room);
user2.setRoom(room);

session.save(room); // 或 session.save(user1), session.save(user2)

產生 SQL:

INSERT INTO room (address) VALUES (?)
INSERT INTO user (name, room_id) VALUES (?, ?)  -- 一次到位,帶 room_id
INSERT INTO user (name, room_id) VALUES (?, ?)
口訣:「多對一雙向關聯,控制權給多的一方(inverse=true 在一的一方),多方負責 set 關聯。」

遺漏關聯的後果

若 User 未 setRoom(room),資料庫 room_id 會是 NULL,等同於「員工沒分配部門」。務必在業務邏輯中保證雙向一致性。

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