【问题标题】:How can I handle/recover a DB Integrity constraint violation exceptions in hibernate?如何在休眠中处理/恢复数据库完整性约束违规异常?
【发布时间】:2015-08-25 22:39:47
【问题描述】:

我正在开发一个使用 JSF 和 hibernate 作为其 ORM 的大型 Web 应用程序。 我的休眠会话很长(用户可以在屏幕上进行大量修改,并且当他按下保存按钮时,更改只会在 DB 上持续存在) 我最近正在努力解决用户修改的回滚/取消问题并寻找不同的解决方案和方法。

我想从违反约束异常(“ORA-02292:完整性约束”)中恢复。

考虑以下场景:
有一个带有记录“x”的表“X”和一个带有记录“y”的表“Y”——其中“x”通过外键取决于“y”。 用户正在尝试删除记录“y”,尽管此步骤将来可能会违反完整性约束, 我没有抛出任何异常,因为用户可以稍后修复它,并且只有当他不修复它并尝试保存屏幕时,数据库才会抛出异常,该异常将聚合到用户界面。

我找不到从这种违规行为中恢复过来的好方法。
在保存过程中,尝试删除记录'y'后,DB按预期启动“ORA-02292:完整性约束”异常。
我的问题是,如果发生这样的错误并且用户确实通过选择另一条记录而不是“y”来修复外键约束,休眠将无法识别它,因为 AFAIK 它仍然会首先尝试删除“y”(因为操作队列)并在执行将“y”替换为另一个实体的操作之前失败。
所以发生的事情是数据库在尝试保存更改时不断触发异常,并且我找不到在不刷新整个屏幕的情况下修复它的方法(这意味着新的休眠会话会丢失所有用户的新数据)。 似乎动作队列保存了删除动作,即使调用 Session “evict” 或 “clear” 方法也不会清除它。

我知道我可以在提交更改之前对其进行验证,并且它可能会起作用,但我对这种解决方案不感兴趣,因为: 1.验证大量可能的更改可能会导致性能问题,此外我相信oracle DB可以为我做得更好。 2. 我不想强制用户执行特定的操作顺序。


更新:

我觉得我应该对申请要求有所了解:
该应用程序的构建方式是,只能在保存阶段提交对 DB 的更改 - 这是用户需求,不幸的是,它不开放讨论
其背后的想法是,用户希望在没有特定顺序的情况下进行更改,并在按下保存按钮之前随时修复错误的数据集。
由于此要求,验证也最好在保存阶段进行。
正如 Dragan Bozanovic 在下面指出的那样,我知道立即验证每个用户修改的可能性,但正如我所说,这不是用户的首选方式。

因此,在我看来,我可以通过三种不同的方式解决问题:
1. 在保存阶段验证所有修改 - 正如我所说,这可能是一个性能问题,因为可能需要进行许多验证。
2. 立即验证每个用户修改 - 这又不是用户的首选选项,但如果必须这样做。
3. 找到一种在数据库级别处理此类场景(完整性约束...)的方法 - 我将不胜感激对此方法的更多建议(如果有)

【问题讨论】:

  • 您考虑过DiSol 的建议吗?您可以将您的实体重新附加(合并)到一个新的会话吗?

标签: oracle hibernate jakarta-ee constraints


【解决方案1】:

你不能,你的事务已经被标记为回滚,即使没有重复删除它也会失败。

解决方案是在数据库中执行数据/操作之前对其进行验证。

但你说你不想要。

“验证大量可能的更改可能会导致性能问题” 但不验证它们可能会导致不一致和错误的保存状态(如果您有难以/不可能在数据库中实现的验证约束)。

“oracle DB 可以为我做得更好” 我不同意。除了外键、not null 和其他一些约束之外,基于 Java 的验证更加灵活和强大。

“我不想强制用户执行特定的操作顺序。” 但是您希望允许他们删除不应删除的内容,然后在 10 分钟后引发错误当他们尝试保存可能相互依赖的累积更改时(并假设删除将成功)。我相信用户会很高兴在尝试执行删除后立即收到错误,以免白白浪费 10 分钟。

我的观点和建议是您应该在指示 Hibernate 删除实体之前进行验证。

【讨论】:

  • "但不验证它们可能会导致不一致和错误的保存状态(如果您有难以/不可能在数据库中实现的验证约束)" 这不准确,因为在当它成功刷新到数据库时,这意味着状态是正确的(至少从数据完整性的角度来看),我想提一下,在某些情况下,当涉及到业务规则时,我们正在验证内容。跨度>
  • "除了外键、not null 和其他一些约束之外,基于 Java 的验证更加灵活和强大。" 我同意你的观点,但这个案例很简单外键之一,据我所知,数据库的强大功能之一是数据完整性,否则,如果我正在验证代码中的所有内容,为什么我根本不应该定义空键和外键,我只能配置我的休眠使用正确的关系并且在数据库级别上没有定义任何内容 - 我相信这种方法是错误的。
  • “但是您希望允许他们删除不应该删除的内容,然后在 10 分钟后尝试保存可能相互依赖的累积更改时引发错误(并假设删除会成功)。我相信用户会在尝试执行删除后立即收到错误消息,以免浪费 10 分钟。“不,我想要允许用户删除一些他可以删除的东西,并让他能够在以后修复错误的数据......
  • ... 我可以给你一个简单的场景,你的方法无法解决:循环关系 - 假设我有 x 引用 y 并且 y 引用回 x (在我的情况下,这个循环可能要复杂得多,并且其中包含 10ns 个实体)-通过您的方法,在创建它之后,用户将永远无法删除它们中的任何一个,因为当他尝试删除 x 时,他会得到一个y 引用它和 x 相同的例外。通过我的方法解决了,因为他可以先删除 x,然后再更改参考。
【解决方案2】:

您可以将模型合并到一个新会话中。你试过了吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-01
    • 2016-06-16
    • 2020-04-22
    • 1970-01-01
    • 2013-03-31
    • 2017-01-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多