Hibernate 級聯操作的關鍵在於:腦中必須建立持久化對象關系樹及狀態圖(Transient、Persistent、Detached)。級聯必須從樹根單向向下傳播,避免雙向級聯導致的死循環與數據不一致。
<class name="User" table="USER">
...
<set name="preferences"
cascade="all,delete-orphan"
inverse="true">
<key column="USER_ID" not-null="true"/>
<one-to-many class="Preference"/>
</set>
...
</class>
<class name="Preference" table="PREFERENCE">
...
<many-to-one name="user" column="USER_ID" not-null="true"
foreign-key="ALLPREFERENCES" class="User"/>
...
</class>
| 屬性 | 含義 | 設置建議 |
|---|---|---|
cascade="all,delete-orphan" |
包含 save/update/delete/lock/merge/replicate + 孤兒刪除 | 樹根集合端聲明,子對象隨父對象生命周期 |
inverse="true" |
關係維護權移交給「多的一方」(Preference) | 必須配合,否則會發雙次 UPDATE 外鍵 |
not-null="true" |
外鍵列非空約束 | 配合 inverse="true" 確保外鍵由多方維護時不為空 |
| 對象狀態 | 推薦方法 | 適用場景 |
|---|---|---|
| Transient (新建) | session.save() |
創建新對象及關聯樹,級聯持久化 |
| Persistent (已托管) | session.flush() / 事務提交 |
修改已加載對象,自動髒檢查同步到 DB |
| Detached (遊離) | update() / saveOrUpdate() / merge() |
跨事務/會話修改,重新關聯到新 Session |
| 任意狀態刪除 | session.delete() |
級聯刪除子對象 (需 delete-orphan) |
ObjectDeletedException: deleted object would be re-saved by cascade原因:手動刪除子對象後,父對象級聯操作又嘗試重新保存它。
解決:從父集合中 remove(child) 後,不要 額外調用 session.delete(child),交由 delete-orphan 自動處理。
Cannot delete or update a parent row: foreign key constraint fails原因:外鍵約束阻止父記錄刪除,因子記錄仍引用它。
解決:確保 cascade="delete" 或 all 生效,或在 DB 層面配置 ON DELETE CASCADE。
user.getPreferences().add(pref); pref.setUser(user); 缺一不可cascade="save-update, merge" 避免全量刪除重建delete-orphan 僅對 one-to-many 集合生效,many-to-one 無效核心口訣:一邊 cascade、一邊 inverse、外鍵 not-null、樹根單向、狀態驅動 API 選擇。