26

私は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)=(testuser@xyz.com) already exists.

ユーザーに意味のある回答を返すにはどうすればよいですか? たとえば、次のようなものです。おっと、誰かがそのメール アドレスを既に使用しているようです。以前に登録したことがありませんか? これを解析するための機能が組み込まれていますか、それとも (おそらく一連の) if ステートメントの例外メッセージに対して正規表現を実行する必要がありますか?

そして、それがビジネス層に引っかかった場合はどうなりますか...プレゼンテーション層にキックアップするためのベストプラクティスは何ですか...前に言ったように、ユーザーに「素敵な」メッセージを提供できるようにします.


明確にするために追加:人々が知っているように、私はさまざまな種類の永続化例外をすべて調べていましたが、持っていて、今も見ています.上記に含めた例:

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

5 に答える 5

6

通常、低レベルの例外を使用してそれを行うことはありません。

代わりに、(クエリを使用して) 電子メールが利用可能であることを明示的に確認し、存在しない場合にのみ電子メールを永続化します。

確かに、2 つのスレッドが同じチェックを並行して行うと、競合状態が発生する可能性がありますが、それは非常にまれであり、一意性を保証するためにデータベースの制約があります。

于 2012-05-08T06:36:01.893 に答える
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 ブロック内の別のクラスに例外とエラー メッセージを送信するように記述します。

于 2012-05-08T06:40:56.837 に答える
3

JPA プロジェクトを Spring と統合し、Spring が例外をスローするようにします。DataAccessException

DataAccessExceptioninのサブクラス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.
于 2014-05-21T12:59:13.503 に答える
3

DB サービス層で同様のことを行って、例外が競合する制約または一般的な DB の障害によって発生したかどうかを判断しています。

try {
....
} catch (final PersistenceException e) {
    final Throwable cause = e.getCause();
    if (cause instanceof MySQLIntegrityConstraintViolationException) {
        throw new ConflictException(cause);
    }
    throw new ServiceException(e);
}
于 2014-05-21T12:39:21.983 に答える