執行 session.persist(entity) 或 session.save(entity) 時拋出:
org.hibernate.PersistentObjectException: detached entity passed to persist: com.example.Entity
Hibernate 判定該實體為 游離狀態,即:
1. 實體擁有非空的標識符(ID);
2. 但該實體不在當前 Session 的管理範圍內(未關聯、或已關閉 Session)。
Hibernate 規定:persist() 僅接受 瞬時狀態 實體(ID 為 null/未賦值);游離實體應使用 merge() 重新關聯。
檢查映射文件或註解:
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // 或 AUTO, SEQUENCE
private Long id;
assigned 策略(手動賦值),確保持久化前 ID 為 null;業務代碼中是否出現:
Entity e = new Entity();
e.setId(100L); // 手動賦值 → 導致實體被視為游離
session.persist(e); // 拋出異常
修正:移除手動 setId,交由 Hibernate 按策略生成。
典型錯誤:構造器重載導致多個 ID 字段:
// 錯誤示例:兩個構造器,第二個帶 id 參數
public Employee(String name, char gender) { ... }
public Employee(Integer id, String name, char gender) { // 多餘 id 參數
super(id, name, gender);
}
Hibernate 實例化實體時可能調用帶 ID 構造器,導致 ID 非 null。
修正:保留無參構造器與業務必需構造器,移除含 ID 參數的構造器。
| 場景 | 實體狀態 | 推薦方法 | 說明 |
|---|---|---|---|
| 新建對象,ID 由數據庫生成 | Transient (瞬時) | persist() / save() | ID 為 null,Hibernate 分配 ID 並納入管理 |
| 新建對象,手動分配業務主鍵 | Transient | persist() | 需配置 @GeneratedValue(strategy=GenerationType.ASSIGNED) |
| 游離對象(來自其他 Session、反序列化、遠程調用) | Detached (游離) | merge() | 返回新的受管實體,原對象不變 |
| 確定對象已在數據庫存在,需更新 | Detached | update() / saveOrUpdate() | 直接關聯到當前 Session,無副本 |
merge() 處理不確定狀態對象,語義更清晰、更安全;hibernate.id.new_generator_mappings=true (默認開啟) 確保生成器行為一致;entity.getId() 及 session.contains(entity) 確認狀態。detached entity passed to persist 本質是「狀態不匹配」:試圖用「新建」語義操作「已存在標識」的對象。通過規範 ID 生成策略、移除手動賦值、清理構造器,配合 merge() 處理游離對象,即可徹底解決。