我在我的Web应用程序中使用EclipseLink,我很难优雅地捕获和处理它生成的异常。我从this thread看到了类似的问题,但我看不出如何解决或修复它。
我的代码如下所示:
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
}
}
当使用违反唯一性约束的实体调用 persist()时,我会收到容器捕获和记录的异常爆炸。
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 :(得分:8)
看起来我不会再对这个问题进行任何活动了,所以我会发布我的解决方案并将其留在那里。许多网络搜索都找不到任何有用的东西。我原以为这是一本教科书案例,但我发现的教程都没有涵盖它。
事实证明,在这种情况下使用EclipseLink,违反SQL约束时可以捕获的异常是 em.com发送()的 RollBackException 强>打电话。所以我修改了这样的持久化方法:
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 :(得分:4)
编辑您的persistence.xml,添加以下属性:
property name =“eclipselink.exception-handler”value =“your.own.package.path.YourOwnExceptionHandler”
现在创建类YourOwnExceptionHandler(在正确的包上)。它需要实现org.eclipse.persistence.exceptions.ExceptionHandler。
创建非参数构造函数和所需方法handleException(...)。
在此方法中,您可以捕获异常!
答案 2 :(得分:3)
EclipseLink应该只抛出PersitenceException或RollbackException,具体取决于环境以及您在EntityManager上调用的操作顺序。 你的日志记录水平是多少?您可能会看到EclipseLink记录这些异常,但仅作为RollbackException的原因而抛出。
您可以使用PU属性关闭异常日志记录,但出于诊断目的,通常最好允许EclipseLink记录异常。
答案 3 :(得分: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;
}
}
答案 4 :(得分: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;
}
有了这个,我不需要为每个Persist编写一个验证程序,它在我的DAO类中很常见。
答案 5 :(得分:1)
2019-12-18
在EclipseLink
服务器上运行的Maven
多模块Web应用程序中,使用{{1} },我将在此处发布我的解决方案,希望为某人节省几个小时。
在Weblogic 12c
中,我们有:
JTA
REST资源类标记有persistence.xml
,这意味着事务从资源类的相关方法接收到请求时开始,并在该方法返回时结束。 >
JTA用于管理交易。
现在,{strong}之后< property name="eclipselink.persistence-context.flush-mode"
value="commit" />
发生在资源类的方法返回(带有对REST客户端的响应)之后。
随后的意思是:
即使您具有非常合适的设置来捕获异常,您仍然 不能,因为像SQLIntegrityConstraintViolationException这样的异常 仅在您的INSERT / UPDATE / DELETE查询之后发生
-一直坐在您的JPA提供者缓存中-,
现在终于发送到数据库了。
发生的情况是在资源类的方法返回之后,并且到那时,所有异常都已被跳过< / strong>。
由于未发送查询==当时未发生异常 当执行通过@Transactional
行时,您无法执行抓住,
但最后,您将在服务器日志中看到异常。
解决方案:
我必须手动在JTA commit time
上调用try{...}catch(Exception e){...}
来强制刷新,并在适当的时间和行(通常在flush()
中发生异常)才能捕获,处理,并允许我的REST方法返回预期的响应。
日志中最后捕获到的异常(我屏蔽了一些不相关的信息):
EntityManager
相关的伪代码:
try block