常見失敗原因
- 外鍵約束違反:
sale_chance.user_id 引用不存在的用戶 ID。
- 事務未提交:Service 方法缺少
@Transactional,Hibernate Session 關閉前未 flush。
- 級聯配置錯誤:
<many-to-one cascade="save-update"> 缺失,關聯對象未持久化。
- 對象狀態混淆:傳入 detached 對象未
merge(),直接 save() 拋異常。
排查步驟
- 開啟 Hibernate SQL 日誌:
hibernate.show_sql=true、hibernate.format_sql=true。
- 捕獲異常堆棧:
try { save(); } catch (Exception e) { log.error(e); throw e; }。
- 檢查數據庫約束:
SHOW CREATE TABLE sale_chance; 確認 FK 定義。
- 驗證用戶 ID 存在:
SELECT * FROM sys_user WHERE id = ?。
正確保存代碼模式
@Transactional
public void assignUser(Long chanceId, Long userId) {
SaleChance chance = chanceDao.get(chanceId); // 已持久化對象
User user = userDao.get(userId); // 確保用戶存在
chance.setUser(user); // 建立關聯
// 無需顯式 save,事務提交時自動 flush
}
最佳實踐
- Service 層統一
@Transactional(rollbackFor = Exception.class)。
- DAO 僅提供
get/load/find,不處理事務。
- 使用
OpenSessionInViewFilter 解決懶加載異常(僅讀場景)。
- 單元測試覆蓋關聯保存邏輯,使用 H2 內存數據庫。