2011-09-12 37 views
12

我在我的web應用程序中使用EclipseLink,並且我很難正常捕捉和處理它生成的異常。我從this thread看到似乎是類似的問題,但我沒有看到如何解決或修復它。如何從EclipseLink捕獲違反約束的異常?

我的代碼如下所示:

public void persist(Category category) { 
    try { 
     utx.begin(); 
     em.persist(category); 
     utx.commit(); 
    } catch (RollbackException ex) { 
      // Log something 
    } catch (HeuristicMixedException ex) { 
      // Log something 
    } catch (HeuristicRollbackException ex) { 
      // Log something 
    } catch (SecurityException ex) { 
      // Log something 
    } catch (IllegalStateException ex) { 
      // Log something 
    } catch (NotSupportedException ex) { 
      // Log something 
    } catch (SystemException ex) { 
      // Log something 
    } 
} 

堅持()被調用,違反唯一性約束的實體,我得到的是捕獲並記錄容器例外爆炸。

Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): 
    org.eclipse.persistence.exceptions.DatabaseException 
Internal Exception: java.sql.SQLIntegrityConstraintViolationException: The statement 
    was aborted because it would have caused a duplicate key value in a unique or 
    primary key constraint or unique index identified by 'SQL110911125638570' 
    defined on 'CATEGORY'. 
Error Code: -1 
(etc) 

我曾嘗試以下:

try { 
     cc.persist(newCategory);   
    } catch (PersistenceException eee) { 
     // Never gets here 
     System.out.println("MaintCategory.doNewCateogry(): caught: " + eee); 
    } catch (DatabaseException dbe) { 
     // Never gets here neither 
     System.out.println("MaintCategory.doNewCateogry(): caught: " + dbe);    
    } 

我意識到,使用DataBaseException是不可移植的,但我需要開始的地方。例外從未被捕獲。有什麼建議麼?

+0

「DataBaseException不可移植」是什麼意思?謝謝! –

+0

@WeishiZeng DataBaseException類由org.eclipse定義,而不是JPA規範。因此,這可能不會與另一個JPA提供者一起工作(甚至不能編譯)。 – AlanObject

回答

8

看起來我不會在這個問題上得到更多的活動,所以我會發布我的解決方法,並將其留在那裏。許多網絡搜索沒有發現很多有用的東西。我原以爲這是一本教科書的案例,但我發現的教程都沒有涵蓋它。

由於它與EclipseLink的這個條件證明,當SQL約束被違反,您可以捕獲該異常是RollBackException那就是em.commit()調用的結果。所以我修改了我堅持的方法是這樣的:

public void persist(Category category) throws EntityExistsException { 
    try { 
     utx.begin(); 
     em.persist(category); 
     utx.commit(); 
    } catch (RollbackException ex) { 
     Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex); 
     throw new EntityExistsException(ex); 
    } catch (HeuristicMixedException ex) { 
     Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex); 
    } catch (HeuristicRollbackException ex) { 
     Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex); 
    } catch (SecurityException ex) { 
     Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex); 
    } catch (IllegalStateException ex) { 
     Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex); 
    } catch (NotSupportedException ex) { 
     Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex); 
    } catch (SystemException ex) { 
     Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex); 
    } 
} 

所以調用者捕捉EntityExistsException並採取適當的行動。日誌仍然充滿了內部異常,但可以稍後關閉。

我意識到這是有點濫用EntityExistsException的意圖,通常只在實體ID字段被重用時使用,但出於用戶應用程序的目的,它並不重要。

如果有人有更好的方法,請發表新的答案或評論。

+1

我也面臨這個問題。我想說明sql約束異常(例如,名字太長,id存在等)。而不是檢查我的代碼中的約束。 (這將是昂貴的檢查唯一的身份證。) –

3

根據您在EntityManager上調用的環境和操作順序,EclipseLink應該只會拋出PersitenceException或RollbackException。 什麼是您的日誌記錄級別?您可能會看到EclipseLink記錄這些異常,但僅作爲RollbackException的原因拋出。

您可以使用PU屬性關閉異常日誌記錄,但出於診斷目的,通常最好允許EclipseLink記錄異常。

+0

正如你所說,我希望在開發模式下保持登錄狀態,以便在出現系統錯誤時能夠發現系統錯誤。但真正的問題是,當我調用** commit()**方法時,我似乎無法捕獲異常,因此我可以在屏幕上向上輸出消息。 – AlanObject

1

我使用Spring Boot 1.1.9 + EclipseLink 2.5.2。這是我可以捕獲ConstraintViolationException的唯一方法。請注意,我的handleError(ConstraintViolationException)是一個非常簡單的實現,它只返回找到的第一個違規。

請注意,當我切換到Hibernate 4.3.7和Hibernate Validator 5.1.3時,還需要此代碼。

看來,添加PersistenceExceptionTranslationPostProcessor exceptionTranslation()到我的持久性JavaConfig類也沒有效果。


import javax.persistence.RollbackException; 
import javax.validation.ConstraintViolation; 
import javax.validation.ConstraintViolationException; 

import org.springframework.http.HttpStatus; 
import org.springframework.http.ResponseEntity; 
import org.springframework.transaction.TransactionSystemException; 
import org.springframework.web.bind.annotation.ControllerAdvice; 
import org.springframework.web.bind.annotation.ExceptionHandler; 

@ControllerAdvice 
class GlobalExceptionHandler 
{ 
    @ExceptionHandler(TransactionSystemException.class) 
    public ResponseEntity<Object> handleError(final TransactionSystemException tse) 
    { 
     if(tse.getCause() != null && tse.getCause() instanceof RollbackException) 
     { 
      final RollbackException re = (RollbackException) tse.getCause(); 

      if(re.getCause() != null && re.getCause() instanceof ConstraintViolationException) 
      { 
       return handleError((ConstraintViolationException) re.getCause()); 
      } 
     } 

     throw tse; 
    } 


    @ExceptionHandler(ConstraintViolationException.class) 
    @SuppressWarnings("unused") 
    public ResponseEntity<Object> handleError(final ConstraintViolationException cve) 
    { 
     for(final ConstraintViolation<?> v : cve.getConstraintViolations()) 
     { 
      return new ResponseEntity<Object>(new Object() 
      { 
       public String getErrorCode() 
       { 
        return "VALIDATION_ERROR"; 
       } 


       public String getMessage() 
       { 
        return v.getMessage(); 
       } 
      }, HttpStatus.BAD_REQUEST); 
     } 

     throw cve; 
    } 
} 
1

我用這個。

if (!ejbGuardia.findByPkCompuestaSiExiste(bean.getSipreTmpGuardiaPK())) { 
    ejbGuardia.persist(bean); 
    showMessage(ConstantesUtil.MENSAJE_RESPUESTA_CORRECTA, SEVERITY_INFO); 
} else { 
    showMessage("Excel : El registro ya existe. (" + bean.toString() + ") ", SEVERITY_ERROR); 
} 

和我從上面的函數:

public boolean findByPkCompuestaSiExiste(Object clasePkHija) throws ClassNotFoundException { 
    if (null != em.find(this.clazz, clasePkHija)) { 
     return true; 
    } 
    return false; 
} 

隨着我不需要編程驗證每一個堅持,它在我的DAO類常見。

+0

不管你在做什麼,不要用西班牙語男子代碼:-D(永遠是英語..) – eav

1

編輯您的persistence.xml添加以下屬性:

屬性名= 「eclipselink.exception處理程序」 值= 「your.own.package.path.YourOwnExceptionHandler」

現在創建類YourOwnExceptionHandler (在正確的包裝上)。它需要實現org.eclipse.persistence.exceptions.ExceptionHandler。

創建一個非參數構造函數和所需的方法handleException(...)。

在這個方法裏面,你可以捕捉異常!

+0

哇,這是一個6年老問題的一個非常驚人的答案。這似乎不是常識。當我再次打開該項目時,我會試一試。 – AlanObject

+0

Alan,我能夠捕獲數據庫異常和錯誤代碼。但是,我仍然試圖將自定義消息發送到我的jsf頁面。 –