2009-07-23 79 views
1

我正在使用Spring和Hibernate。和Atomikos交易。我使用基於註釋的交易。我有一個DAO對象,並且在我調用entityManager.persist()來保存對象的方法之一中。 現在,無論何時在更新期間出現ORA錯誤,例如違反約束或其中一列的長度超過數據庫中的wat,我都會得到一個JTAUnexpectedRollbackException,而不是Spring引發的GenericJDBCException。 我嘗試過嘗試一下,堅持抓住,但我沒有得到任何例外。看起來Hibernate在刷新過程中會執行實際的更新語句,這發生在事務提交期間,因此我猜UnexpectedRollbackException。Hibernate刷新和JTAUnexpectedRollbackException異常

如何解決此問題並獲取GenericJDBCException而不是UnexpectedRollbackException?

+0

爲什麼獲取GenericJDBCException而不是JTAUnexpectedRollbackException非常重要?爲什麼要在持久存儲上捕獲異常,而不是在事務提交時執行? – 2009-07-27 08:56:03

回答

1

首先,免責聲明:我不使用Atomikos。我不認爲它與有問題的錯誤有任何關係,但不能確定。

前段時間我在Spring/Hibernate應用程序中遇到過類似的問題。 Hibernate確實只會在刷新期間將會話更新傳播到數據庫。問題在於可能會在不同的時間發生刷新,具體取決於刷新模式。它默認爲AUTO,這意味着如果會話包含可能影響查詢結果的更新,則在查詢執行之前可能會發生刷新。您有幾種選擇:

A)您可以在撥打entityManager.persist()後立即手動呼叫entityManager.flush()並在該點捕獲異常(如果有)。這個缺點(可能或不適用於你的情況)是flush會中斷批量更新,所以如果你在單個事務中對同一個實體類型進行多次插入/更新,你可能會遇到(可能)顯着的性能下降。 B)你可以將你的flush模式設置爲COMMIT,這會延遲刷新,直到事務被提交(或者直到手動調用flush())。然後您可以在該點捕獲異常,或者如果由於Atomikos而證明不可能,則可以在提交之前(例如在服務調用結束時)手動調用flush()。缺點是這比選項A更難(對我來說這很難,Atomikos可能會更難 - 我不知道),並且您的查詢可能會返回過時的數據。

1

如果UnexpectedRollbackException包含GenericJDBCException,因爲它的原因或幾個原因下游,程序可以用getCause()getRootCause()方法取出並重新把它扔。

try { 
    em.flush(); 
} catch (UnexpectedRollbackException e) { 
    if (e.getRootCause() instanceof GenericJDBCException) { 
     throw e.getRootCause(); 
    } 
} 

我不知道如果getRootCause()或的getCause()[.getCause()返回GenericJDBCException,你會發現它,也許有一個調試器。