2012-05-08 11 views
24

Ben JPA için oldukça yeni ve JPA'nın kalıcılık istisnalarını ele alırken en iyi uygulamaları bulmak istiyorum, örneğin adresinin ele alınabileceği benzersiz kısıtlama ihlalleri kullanıcı tarafından. JPA uygulamalarının nasıl yazılacağı konusunda pek çok örnek vardır, ancak istisnaların nasıl elden çıkarılacağı konusunda neredeyse hiçbir şey yoktur. Örneğin:Kullanıcıya anlamlı bir ileti vermek için JPA kalıcılık istisnalarını nasıl ele alıp ayrıştırıyorsunuz?

bir kullanıcının kaydedilmesi /, kişi sistem tarafından aktif zaten kullanımda ve bir kısıtlama ihlali alır email adresini girer: yinelenen bir e-posta eklenir bu hatayı üretir

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. 

Kullanıcıya nasıl anlamlı bir yanıt verebilirim? Mesela şöyle bir şey var: Oops birileri o e-posta adresini kullanıyor gibi görünüyor, daha önce kaydetmediğinize emin misiniz? Bunu ayrıştırmak için bir tesis var mı, yoksa bir istisna mesajına karşı (muhtemelen bir dizi) deyim (ler) ibaresiyle regex çalıştırmam gerekecek mi?

Ve iş katmanında yakalanıp yakalanmayacaksa ... sunum seviyesine tekabül etmek için en iyi yöntemler nelerdir ... daha önce de söylediğim gibi, bu yüzden “güzel” bir mesaj verilebilir. kullanıcı. netlik için


Eklendi: kişi bilesin ki, ben, var ve hala burada kalıcılık istisnalar her çeşit bakıyor ve am araştırmanın bazı ben yapmadım yapıyorum olduğunu' t yukarıda yer "deyimi deneyin" örnekle şunlardır:

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()); 
    } 

:)

cevap

4

You tipik bunu düşük seviye istisnaları kullanmayın. Bunun yerine, e-postanın kullanılabilir olduğunu (bir sorgu kullanarak) açık bir şekilde kontrol edersiniz ve e-postayı yalnızca mevcut değilse görürsünüz.

Elbette, iki iş parçacığının aynı denetimi aynı paralelde yapması durumunda bir yarış durumu olabilir, ancak çok nadir olacak ve benzersizliği garanti etmek için veritabanı kısıtlaması var olacaktır.

+0

içinde DataAccessException arasında DataAccessException

altsınıflar olarak istisnalar @version açıklama bizi olabilir ırk durumunu ortadan kaldırmak için ed? Nasıl çalışır? Düşündüğünüzü kontrol etmeyi düşündüm, ama yarış durumu beni endişelendirdi ve hala öyle. Dediğin gibi, şanslar düşüktür; ama bu sadece nadiren de olsa gerçekleşeceği anlamına geliyor, bu yüzden hala ele alınması gerekiyor. Bunun, özellikle kullanıcı adı ve req'd e-posta adresinin her ikisinin de benzersiz olması gerektiğine izin vermek istiyorsanız, kullanıcının dahil olması gereken nadir kullanım durumlarından biri olduğunu kabul ediyorum. FWIW, yüksek hacimli bir dünyadan geliyorum (DB'lerin/100'lerin Ks'nin 100'leri/sz) bu yüzden gereksiz DB isabetleri konusunda kibirli oluyorum. :) – BillR

+0

Ayrıca, sanırım ki bu iş katmanında sunum katmanına kadar yakalanan kalıcılık istisnasını atacaktı. Böyle bir kullanıcı adresli kısıtlama hatası meydana geldiğinde, yani (nadiren de olsa, bunun gerçekleşeceği anlamına geldiğine inanıyoruz): D). Ya da muhtemelen her durumda ve sunum katmanı kullanıcının ne yapması gerektiğini ve ne kadar sinir bozucu (kullanıcı için) hata sayfası olsa da neyin hoşuna gideceğini sorar. Bu arada giriş için teşekkürler. – BillR

+1

@Version burada herhangi bir amaca hizmet eder: her iki ileti zaten bir e-postanın var olup olmadığını kontrol eder, her ikisi de onu bulamaz ve her ikisi de eklemeye çalışır. Yarış koşulu, sonunda veritabanındaki benzersiz kısıtlama ile çözülecektir. Bu durumda, kullanıcıya genel bir hata iletisi görüntülersiniz veya başarısız olan işlemi otomatik olarak yeniden denersiniz. Yeniden denemenin (özellikle daha önce küçük bir gecikme kullanırsanız) e-postanın olduğunu bulmak için iyi bir şansı vardır ve kullanıcıya anlamlı bir hata mesajı gösterir. –

3

PersistenceException alt sınıfları vardır: EntityExistsException, EntityNotFoundException, NonUniqueResultException, NoResultException, OptimisticLockException, RollbackException, TransactionRequiredException. Kaynak: http://docs.oracle.com/javaee/5/api/javax/persistence/PersistenceException.html

Bunları kullanabilirsiniz. İstisna türünü kontrol etmeye veya bir hata işleme yöntemini yüklemeye çalışın (hangisi daha iyi). EntityExistsException Yukarıda verdiğiniz örnekte aradığınız hatayı düşünüyorum. Ama kendiniz "var ise" kontrol etmelisiniz. Bu en iyi uygulama.

SQL Hatası, kullanıcıya gösterilmesi için hiçbir zaman gerekli olmamalıdır. Bu hata her zaman senin için. Kullanıcıyı bilgilendirmek için gereken herhangi bir veri hatası manuel olarak kontrol edilmelidir.

J2EE Web Ortamını kullanıyorum. Bir istisna varsa, yalnızca error.jsp isteğini iletiyorum. Ayrıca kullanıcı geri dönebilir, hatadan sonra hangi sayfaya gidebilir gibi bilgileri açıklığa kavuşturmak için error.jsp için ekstra bir nesne de sağlarım. Tabii ki bunu otomatikleştirdim, gereksiz kod yazmaktan hoşlanmıyorum çünkü güncellenmesi zor.Bu yüzden istisna ve hata mesajını catch bloğundaki başka bir sınıfa yazarım.

+0

SQL hata mesajını kullanıcıya sızmamanız gerektiğini kabul ediyorum. Her ne kadar bir Dahili Sunucu Hatası veya Kötü Bir İstek (kullanıcı hatası) arasında bir fark yaratmak için uygun hata işleme uygulanmalıdır. Çatışma için ön sorgulama, yarış durumu hala geçerli olduğundan bu sorunu çözmez. – Pepster

1
ben istisna çakışan kısıtlaması veya genel DB hatası neden olup olmadığını anlamaya benim DB hizmet katmanda benzer bir şey yapıyorum

:

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

Bahar ile JPA projeyi entegre ve izin bahar atmak 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

Birkaç yıl önce Spring'i denedim ve kişisel olarak 'XML Hell''den şikayet eden insanlarla tanıştım. Özgün Java EE'den nefret ettiğime dikkat et (ve bu yüzden neden Baharın varlığını anladığımı anlıyorum). Ama ben Java ile ilgili bir şey yapmak istemediğim noktaya dayanamıyorum. JEE6'dan beri geri döndüm ve daha sezgisel ve daha temiz olan 'resmi' JEE'yi buldum. Yine de baharı tekrar gözden geçireceğimi sanmıyorum. – BillR

İlgili konular