2012-05-08 40 views
24

我對JPA相當陌生,並且希望找到處理JPA中的持久性異常的最佳實踐,比如說,可以解決可以解決的唯一約束違例問題由用戶。有很多關於如何編寫JPA應用程序的示例,但幾乎沒有關於如何處理由它們拋出的異常的示例。 :/如何處理和解析JPA持久性異常,以向用戶提供有意義的消息

例如註冊用戶,該人進入的電子郵件地址已經在由系統積極利用和得到一個約束違反:

try { 
    em.persist(credentials); 
} catch (javax.persistence.PersistenceException ex) { 

產生當添加重複的電子郵件此錯誤:

WARNING: SQL Error: 0, SQLState: 23505 
SEVERE: ERROR: duplicate key value violates unique constraint "EMAIL_UQ_IDX" 
    Detail: Key (email)=([email protected]) already exists. 

如何獲得有意義的答案給用戶?例如:Oops看起來像有人正在使用該電子郵件地址,你確定你以前沒有註冊過嗎?是否有內置的解析器,或者是否需要針對異常消息運行正則表達式(可能是一系列)if語句?

如果它在業務層上被捕獲,怎麼辦......將它踢到表示層的最佳實踐是什麼......就像我之前說過的那樣,這樣可以爲用戶。


增加對淨度: 正是這樣的人都知道,我有,有,而且我仍然在尋找各種不同類型的持久性的異常,這裏是一些研究,我一直在做我不」牛逼包括與我上面包括「try語句」例如:

try { 
    em.persist(credentials); 
    } catch (javax.persistence.PersistenceException ex) { 
     System.out.println("EXCEPTION CLASS NAME: " + ex.getClass().getName().toString()); 
     System.out.println("THROWABLE CLASS NAME: " + ex.getCause().getClass().getName().toString()); 
       Throwable th = ex.getCause(); 
     System.out.println("THROWABLE INFO: " + th.getCause().toString()); 
     Logger.getLogger(CredentialsControllerImpl.class 
       .getName()).log(Level.INFO, "Credentials Controller " 
        + "persistence exception " 
         + "EXCEPTION STRING: {0}", ex.toString()); 
     Logger.getLogger(CredentialsControllerImpl.class 
       .getName()).log(Level.INFO, "Credentials Controller " 
        + "persistence exception " 
         + "THROWABLE MESSAGE: {0}", th.getMessage()); 
     Logger.getLogger(CredentialsControllerImpl.class 
       .getName()).log(Level.INFO, "Credentials Controller " 
        + "persistence exceptions " 
         + "THROWABLE STRING: {0}", th.toString()); 
    } 

:)

回答

4

你通常不使用低級別的異常做到這一點。

取而代之,您明確地檢查電子郵件是否可用(使用查詢),並且只有在電子郵件不存在時才允許使用該電子郵件。

當然,如果兩個線程並行執行相同的檢查,可能會出現競爭狀況,但這種情況非常罕見,並且數據庫約束可以保證唯一性。

+0

的@Version註解能我們編輯消除競爭條件?它將如何工作?我曾想過按照你的建議檢查前線,但比賽狀況令我擔憂,現在仍然如此。正如你所說,機會很低;但這只是意味着它仍然會發生,儘管很少,所以仍然需要處理。我承認這是用戶需要參與的罕見用例之一,特別是如果您想允許用戶名和要求的電子郵件地址都必須是唯一的。 FWIW,我來自大量的世界(數據庫事務處理的K個百位數/秒),所以我得到了不必要的數據庫命中。 :) – BillR

+0

此外,我想不用說,人們會拋出業務層中的持續性異常,直到表示層。當這樣的用戶可尋址約束錯誤發生時,就是(就像我們同意它即使很少......這意味着它會發生:D)。或者可能在所有情況下,表現層決定它要求用戶修復哪些內容,以及它會令人滿意,但是(對用戶)錯誤頁面令人沮喪。感謝您輸入的方式。 – BillR

+1

@Version可以用於這裏的任何目的:這兩個線程會檢查一個電子郵件是否已經存在,兩者都不會找到它,並且都會嘗試插入。競爭條件最終將通過數據庫中的唯一約束來解決。在這種情況下,要麼向用戶顯示一條通用錯誤消息,要麼自動重試失敗的事務。重試有一個很好的機會(特別是如果你使用一個小的延遲之前)發現電子郵件存在,並將顯示一個有意義的錯誤信息給用戶。 –

3

存在PersistenceException的子類:EntityExistsException,EntityNotFoundException,NonUniqueResultException,NoResultException,OptimisticLockException,RollbackException,TransactionRequiredException。 來源:http://docs.oracle.com/javaee/5/api/javax/persistence/PersistenceException.html

你可以使用它們。嘗試檢查異常的類型或重載錯誤處理方法(哪個更好)。 EntityExistsException我想你在上面給出的例子中搜索的錯誤。但是你應該自己檢查「是否存在」。這是最佳做法。

SQL錯誤應該永遠不需要顯示給用戶。這個錯誤總是給你的。任何需要通知用戶的數據相關錯誤都必須手動檢查。

我使用J2EE Web環境。如果有異常,我只是將請求轉發給error.jsp。我還爲error.jsp提供了一個額外的對象來澄清用戶可以返回的信息,錯誤後可以去哪個頁面等。當然,我自動化了這一點,我不喜歡編寫冗餘代碼,因爲它很難更新。所以我只是寫了catch塊的另一個類發送異常和錯誤消息。

+0

我同意你不應該向用戶泄漏SQL錯誤消息。雖然應該實施適當的錯誤處理來區分例如內部服務器錯誤或錯誤請求(用戶錯誤)。預先查詢衝突並不能解決這個問題,因爲競爭條件仍然適用。 – Pepster

1

我做我的DB服務層類似的東西弄清楚是否異常是由矛盾的約束或普通DB故障引起:

try { 
.... 
} catch (final PersistenceException e) { 
    final Throwable cause = e.getCause(); 
    if (cause instanceof MySQLIntegrityConstraintViolationException) { 
     throw new ConflictException(cause); 
    } 
    throw new ServiceException(e); 
} 
3

整合您的JPA項目,春讓Spring拋出例外情況DataAccessExceptionDataAccessException

子類中org.springframework.dao

class CannotAcquireLockException 
     Exception thrown on failure to aquire a lock during an update, for example during a "select for update" statement. 
class CannotSerializeTransactionException 
     Exception thrown on failure to complete a transaction in serialized mode due to update conflicts. 
class CleanupFailureDataAccessException 
     Exception thrown when we couldn't cleanup after a data access operation, but the actual operation went OK. 
class ConcurrencyFailureException 
     Exception thrown on concurrency failure. 
class DataAccessResourceFailureException 
     Data access exception thrown when a resource fails completely: for example, if we can't connect to a database using JDBC. 
class DataIntegrityViolationException 
     Exception thrown when an attempt to insert or update data results in violation of an integrity constraint. 
class DataRetrievalFailureException 
     Exception thrown if certain expected data could not be retrieved, e.g. 
class DeadlockLoserDataAccessException 
     Generic exception thrown when the current process was a deadlock loser, and its transaction rolled back. 
class EmptyResultDataAccessException 
     Data access exception thrown when a result was expected to have at least one row (or element) but zero rows (or elements) were actually returned. 
class IncorrectResultSizeDataAccessException 
     Data access exception thrown when a result was not of the expected size, for example when expecting a single row but getting 0 or more than 1 rows. 
class IncorrectUpdateSemanticsDataAccessException 
     Data access exception thrown when something unintended appears to have happened with an update, but the transaction hasn't already been rolled back. 
class InvalidDataAccessApiUsageException 
     Exception thrown on incorrect usage of the API, such as failing to "compile" a query object that needed compilation before execution. 
class InvalidDataAccessResourceUsageException 
     Root for exceptions thrown when we use a data access resource incorrectly. 
class OptimisticLockingFailureException 
     Exception thrown on an optimistic locking violation. 
class PermissionDeniedDataAccessException 
     Exception thrown when the underlying resource denied a permission to access a specific element, such as a specific database table. 
class PessimisticLockingFailureException 
     Exception thrown on a pessimistic locking violation. 
class TypeMismatchDataAccessException 
     Exception thrown on mismatch between Java type and database type: for example on an attempt to set an object of the wrong type in an RDBMS column. 
class UncategorizedDataAccessException 
     Normal superclass when we can't distinguish anything more specific than "something went wrong with the underlying resource": for example, a SQLException from JDBC we can't pinpoint more precisely. 
+0

幾年前,我嘗試過Spring,並且我個人認同那些抱怨'XML地獄'的人。請注意,我討厭原始的Java EE(這也是爲什麼我理解Spring爲什麼會出現)。但我無法忍受這兩點,我不想與Java有任何關係。自JEE6以來,我回來了,發現'官方'JEE產品更直觀,更清潔。但我不認爲我會重溫春天。 – BillR

相關問題