2014-03-06 38 views
0

我正在做一個Primefaces的Web項目,它發送並從使用JPA的遠程EJB獲取數據。我得到這個代碼來處理的獨特價值,在實體Bean設置unique=true後:如何從JPA唯一約束違規中獲取值?

try{ 
    emsave.persist(newItem); 
} catch (PersistenceException pe){ 
    System.out.println("dupe found"); 
} 

然後我回滾事務。 在Eclipse控制檯我得到這些消息從JBoss作爲:

09:15:12,179 WARN [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (http-localhost-127.0.0.1-8189-6) SQL Error: 1062, SQLState: 23000 
09:15:12,179 ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (http-localhost-127.0.0.1-8189-6) Duplicate entry 'asdasd' for key 'username' 

我要送,不能保存回前端對象,並在表格中顯示出來,或在表某種程度上標誌着他們如此該用戶知道他必須改變什麼。我有辦法怎麼做,但我不知道如何標記什麼領域有壞的價值。是否有可能得到這個'用戶名'字段填寫不正確,從這個異常,或者應該使用其他方式?我正在尋找最優雅的解決方案。

回答

2

首先,persist()是不是會拋出異常。 persist()僅通過將該對象附加到持久性上下文來將該對象標記爲持久對象。實際插入將在沖洗時發生。

其次,似乎你想在循環中做到這一點。所有運行時的exeptions都是不可恢復的,並且使上下文處於不可靠的狀態。只要你得到一個異常,當前事務應該被回滾,你不應該繼續使用實體管理器。

最後,這兩個事實和常見的良好實踐導致瞭解決方案:您不應該依賴異常來檢測不正確的值。如果名稱應該是唯一的,那麼您應該發出一個查詢來測試輸入的名稱是否已經存在於表中,並且只有在您驗證了所有內容後才插入。當然,你可以在兩個併發事務之間有一個競爭條件,但這種情況不會經常發生,因此你可以使用通用的「Oops」錯誤消息來處理它(或者如果真的需要重試該事務)。

+0

在flush()期間拋出異常的好處。 – AlexR

+0

我只發佈了一小段代碼,我稍後回滾事務,但我仍然循環直到數據結束,所以我不能發回所有錯誤的東西。它只是這個應用程序將來會被很多用戶使用,我的意思是ALOT,所以我想限制完成的查詢量。這個特定的表格可能會被管理員使用,很少,但我仍然在尋找最好的方式來做事。因此,檢查唯一身份的最佳方法是在每次插入/更新之前進行查詢以檢查欺騙? – Candyman

+0

不,我立即得到異常,但由於我使用的是實體事務,通過捕獲這個事務被做成rollBackOnly,所以.commit()會導致我一個真正的錯誤,使EJB中斷。 – Candyman

1

有沒有好辦法做到這一點。問題是JPA不自己驗證數據庫約束。它只是將此檢查委託給底層數據庫。所以,具體的異常由JDBC驅動程序拋出,並由PersistenceException包裝。你顯然可以調用pe.getCause()(甚至可能兩次 - 查看使用調試器拋出什麼樣的異常)並嘗試處理異常消息。但請注意,這可能取決於底層數據庫和/或其JDBC驅動程序。

但是:通常創建基於異常的流程是非常糟糕的做法。您應該自己驗證您的應用程序級別的「約束」,並且如果可能存在唯一的約束違規,則不要嘗試執行操作。無論如何,無論如何都是無用的:用戶應該嘗試再次執行操作。用戶不應該能夠執行「錯誤的」操作:UI應該保護他。

+0

感謝您的想法,我正在回答問題:) – Candyman