如何从 EclipseLink 捕获约束违规异常?
我在 Web 应用程序中使用 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
}
}
当使用违反唯一性约束的实体调用 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 不可移植,但我需要从某个地方开始。例外永远不会被捕获。有什么建议吗?
I am using EclipseLink in my web application, and I am having a hard time gracefully catching and handling Exceptions it generates. I see from this thread what seems to be a similar problem, but I don't see how to work around or fix it.
My code looks like this:
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
}
}
When persist() is called with an entity that violates a uniqueness constraint, I get an explosion of exceptions that are caught and logged by the container.
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)
I have tried the following:
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);
}
I realize that using DataBaseException is not portable, but I need to start somewhere. The exceptions never get caught. Any suggestions?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
看起来我不会再对这个问题进行任何活动,因此我将发布我的解决方法并就此保留。许多网络搜索都没有找到太多有用的东西。我本以为这是教科书案例,但我找到的教程都没有涵盖它。
事实证明,在 EclipseLink 的这种情况下,违反 SQL 约束时可以捕获的异常是 RollBackException,它是 em.commit() 调用的结果。所以我修改了我的 persist 方法,如下所示:
因此调用者捕获 EntityExistsException 并采取适当的操作。日志仍然充满内部异常,但可以稍后关闭。
我意识到这有点滥用 EntityExistsException 的意图,该意图通常仅在重新使用实体 ID 字段时使用,但出于用户应用程序的目的,它并不使用事情。
如果有人有更好的方法,请发布新答案或评论。
It looks like I won't get any more activity on this question, so I will post my work-around and leave it at that. A number of web searches haven't found much of anything that is helpful. I would have thought this is a textbook case but none of the tutorials I have found covers it.
As it turns out in this condition with EclipseLink, the Exception you can catch when the SQL constraint is violated is the RollBackException that is the result of the em.commit() call. So I have modified my persist method like this:
So the caller catches the EntityExistsException and takes the appropriate action. The log still fills up with the internal exceptions but that can be shut off later.
I realize that this is a bit of an abuse of the intent of the EntityExistsException that is normally only used when an entity ID field is re-used, but for the purposes of the user application it doesn't matter.
If anyone has a better approach please post a new answer or comment.
编辑 persistence.xml 添加以下属性:
property name="eclipselink.exception-handler" value="your.own.package.path.YourOwnExceptionHandler"
现在创建类 YourOwnExceptionHandler (在正确的包上)。它需要实现 org.eclipse.persistence.exceptions.ExceptionHandler。
创建一个无参数构造函数和所需的方法handleException(...)。
在这个方法中,你可以捕获异常!
Edit your persistence.xml adding the following property:
property name="eclipselink.exception-handler" value="your.own.package.path.YourOwnExceptionHandler"
Now create the class YourOwnExceptionHandler (on the correct package). It requires to implement org.eclipse.persistence.exceptions.ExceptionHandler.
Create a non argument constructor and the required method handleException(...).
Inside this method, you can catch the exceptions!
EclipseLink 应该只抛出 PersitenceException 或 RollbackException,具体取决于环境以及您在 EntityManager 上调用的操作顺序。
您的日志记录级别是多少?您可能会看到 EclipseLink 记录的这些异常,但仅作为 RollbackException 的原因抛出。
您可以使用 PU 属性关闭异常日志记录,但出于诊断目的,通常最好允许 EclipseLink 记录异常。
EclipseLink should only be throwing either a PersitenceException or a RollbackException depending on the environment and the order of operations you are calling on the EntityManager.
What is your logging level? It is likely that you are seeing these exceptions logged by EclipseLink but only thrown as causes of the RollbackException.
You can turn off exception logging with the PU property but for diagnostic purposes it is generally better to allow EclipseLink to log the exceptions.
2019-12-18
由于这是一个非常受关注的问题,我刚刚在
Maven
多模块网络中遇到了与EclipseLink
非常相似的问题应用程序在Weblogic 12c
服务器上运行并使用JTA
,我将在这里发布我的解决方案,希望能为某人节省几个小时。在
persistence.xml
中,我们有:REST 资源类被标记为
@Transactional
,这意味着事务在相关对象收到请求时开始。资源类的方法,当该方法返回时结束。JTA 用于管理事务。
现在,
JTA 提交时间
恰好发生在资源类的方法返回(带有对 REST 客户端的响应)之后。这意味着:
发生在资源类的方法返回之后,并且此时,所有异常都已被跳过 。
由于没有发送查询==没有发生异常在执行
try{...}catch(Exception e){时
...}
行,您无法捕捉到它,但最后,您将在服务器日志中看到异常。
解决方案:
我必须在
EntityManager
上手动调用flush()
来强制刷新并在适当的时间和行发生异常(基本上在try 块
>) 能够捕获它、处理它,并允许我的 REST 方法返回我想要的响应。最终捕获日志中的异常(我屏蔽了一些不相关的信息):
相关伪代码:
2019-12-18
As its a very well viewed question and I just had a very similar issue with
EclipseLink
, in aMaven
multi module web application running onWeblogic 12c
server and usingJTA
, I am going to post my solution here, hoping to save a couple hours for someone.In the
persistence.xml
we are having:The REST resource class was marked with
@Transactional
, meaning that the transaction starts at the point when the request has been received by the related method of the resource class, and it ends when this method returns.JTA used for managing the transactions.
Now,
JTA commit time
happens to occur AFTER the resource class's method returns (with a response to the REST client).Which subsequently means that:
Which happens just after the resource class's method returns, and at that point, all the exceptions has been skipped already.
Since no query sent == no exception occured at the time when the execution ran through the
try{...}catch(Exception e){...}
lines, you were not able to catch it,but at the end, you will see the exception in the server's log.
Solution:
I had to manually call
flush()
onEntityManager
to force flush and the exception to occur at the proper time and line (basically in thetry block
) to be able to catch it, handle it, and allow my REST method to return with my intended response.The final caught exception in the log (I have masked some not related info):
Related pseudo code:
我正在使用 Spring Boot 1.1.9 + EclipseLink 2.5.2。这是我捕获 ConstraintViolationException 的唯一方法。请注意,我的
handleError(ConstraintViolationException)
是一个非常简单的实现,它仅返回它找到的第一个违规。请注意,当我切换到 Hibernate 4.3.7 和 Hibernate Validator 5.1.3 时,也需要此代码。
似乎将
PersistenceExceptionTranslationPostProcessor exceptionTranslation()
添加到我的持久性 JavaConfig 类也没有效果。I'm using Spring Boot 1.1.9 + EclipseLink 2.5.2. This is the only way I can catch ConstraintViolationException. Note that my
handleError(ConstraintViolationException)
is a very simple implementation which just returns the first violation it finds.Note that this code was also required when I switched to Hibernate 4.3.7 and Hibernate Validator 5.1.3.
It seems that adding
PersistenceExceptionTranslationPostProcessor exceptionTranslation()
to my persistence JavaConfig class also has no effect.我用这个。
以及我上面的函数:
这样我就不需要为每个 Persist 编写验证程序,它在我的 DAO 类中很常见。
I use this.
and my function from above:
With that I dont need to program a validation for each Persist, its common in the my DAO Classes.