12

假设我有 columnGender和 constraint CHECK( Gender IN ('F', 'M', 'OTHER'))
如果我不小心忘记在客户端处理这个问题,用户会看到这样的东西
ORA-02290: check constraint (SYS_C099871244) violated
,这对用户和维护或调试的开发人员都不是很有帮助

有没有办法提供开发人员定义的消息,如(伪)Java 的
assert Gender IN (0,1):'Gender must be F or M'

我能想到的唯一方法是将约束移动到 BEFORE UPDATE OR INSERT 触发器和失败时执行Raise_Application_Error( code, my_message )。但我不喜欢它

编辑 具体原因列表,根据评论
1. 我真的很喜欢让逻辑尽可能接近数据
2. 对于最终用户 Raise_Application_Error 消息与应用程序消息无法区分
3. 开发人员会看到很好的消息,即使访问数据绕过应用程序
4. 将约束移动到触发器是丑陋的(是吗?),所以我必须找到与 Raise_Application_Error 不同的东西

EDIT2 1,5 年后,在我离开与 db 相关的工作之后,我终于想到了,我真的不喜欢这个 -代码重复。我必须在服务器端和客户端重复完全相同的逻辑。最有可能,使用 2 种不同的语言。并使它们保持同步。这太丑了。

尽管答案清楚地表明,对此我无能为力。所以现在是我成为好公民并最终接受答案的时候了(抱歉,刚刚忘记了)。

4

4 回答 4

9

约束是数据库用来保护自己免受错误应用程序而不是用户的影响。

这意味着应用程序应捕获违反约束的情况,并可能进行清理以呈现给用户。我认为没有这样做的应用程序在某种程度上存在缺陷。

我说“可能”,因为您的应用程序(至少在这种情况下)永远不会看到这种情况发生。几乎可以肯定,它应该使用下拉限制选择控件来处理类似的事情。如果它使用组合框或(震惊,恐怖)自由格式的文本输入字段,则需要重新定义。

这意味着违规永远不会发生,当然,除非应用程序和约束在某些时候不同步。但这是应该在测试中抓住的东西,早在客户得到他们肮脏的小手之前就可以使用您的应用程序。


要回答您的实际问题,不能更改从 Oracle 发出的违反约束的消息。您能做的最好的事情就是智能地命名您的约束,以便它对最终用户有意义。

但我仍然认为,向用户展示问题是应用层的责任,而不是数据库层的责任。

于 2011-05-20T07:36:23.243 回答
5

如果您正在寻找一种方法来告诉 Oracle 始终将异常消息“ORA-02290:违反检查约束 (SYS_C099871244)”替换为另一条消息,例如“ORA-20001:性别必须是 F 或 M”,那么答案是:不,这是不可能的。

您可以做的是提供一个可供开发人员在其代码中使用的解决方案,如下所示:

...
begin
    insert into emp (empno, gender) values (p_empno, p_gender);
exception
    when others then
       error_pkg.handle_exception;
end;

error_pkg.handle_exception过程将解析 Oracle 异常消息并提取约束的名称(如果它是违反约束的)并在交叉引用表中查找该约束名称以获取所需的消息,然后使用raise_application_error新的重新引发异常信息。

我想 Oracle 可以提供这样的包和表作为标准,但也许由于在实践中对系统中的错误处理有许多不同的要求,因此通常认为它不够有用。

于 2011-05-20T09:01:44.690 回答
4

简而言之:据
我所知,无法捕获用于自定义处理的 oracle 错误。但是,我认为您无论如何都不应该尝试这样做。


加长版:
你的理由背后的意图是好的,但是......

我真的很喜欢让逻辑尽可能接近数据

逻辑应该尽可能接近数据,这是真的;然而这不符合条件——这不是逻辑,这是识别已定义逻辑异常的代码表示并且表示不应与数据或逻辑层混合(错误消息的域跨越系统的每个部分;从客户端到服务器端,还要考虑翻译、一致更新、更轻松的管理和消息概览等...)

对于最终用户 Raise_Application_Error 消息与应用程序消息无法区分

没错,但反过来也是有效的,因此不是特别相关 - 如果您有 DB 错误代码、应用程序错误代码和错误处理的中央存储库将处理它,那么(对于最终用户)哪个层呈现错误消息是无关紧要的. 此外,从长远来看,尚不清楚它是否会为您节省任何工作。

即使绕过应用程序访问数据,开发人员也会看到很好的消息

这是真的,对于直接访问 DB 的开发人员来说,会有更好的错误消息。这里仍然有一些评论 - 在复杂的系统中不应允许绕过应用程序层(即使对于开发人员);如果允许,您希望开发人员知道从约束名称中查找错误消息的位置(错误代码和消息的中央存储库应该/将在同一个数据库中维护)

将约束移动到触发器是丑陋的(是吗?),所以我必须找到与 Raise_Application_Error 不同的东西

从某种意义上说,它是一种表现形式,不应该在 DDL 中,这很丑陋。此外,如果通过触发器完成,它会导致不合理的(?)性能损失(不确定有多大,也不确定它可以做得多么优雅)。

注意:总而言之,我同意有可能挂钩 DBMS 错误处理将是一个很好的功能。

但是,错误处理和错误消息处理具有以下属性

  • 需要可维护(理论上,这可以通过在信息模式中存储自定义错误消息来干净地完成,但 SQL 标准没有指定,所以这纯粹是理论上的评论 - 实际上,您必须拥有自己的表来实现这些目的)

而且,更重要的是

  • 错误消息处理是上下文相关的(从数据客户端的角度来看,错误处理程序会得到最大的通知 - 有时相同的错误代码可能需要不同的表示,不同的消息)
于 2011-05-20T09:50:44.507 回答
3

无论约束是向客户提出还是记录在文件中以供支持人员进行(潜在)分析,您都应该得到更有用的消息。

如果你命名你的约束,它会更有帮助。

我会去做类似的事情

ALTER TABLE blah ADD CONSTRAINT blah_gender_ck CHECK ( Gender IN ('F', 'M', 'OTHER'));
于 2011-05-20T08:35:46.003 回答