编写 ESQL 代码以处理错误

介绍

在消息流中处理消息时,以下原因可能导致错误:
  1. 外部原因。例如,入局消息在语句构成上是无效的,流使用的数据库已经关闭,或运行代理的机器的电源发生故障。
  2. 内部原因。例如,由于约束阻碍导致尝试向数据库表插入行失败,或由于从数据库读取的字符串包含字母字符,无法将它转换为数字。

    内部错误可能是由程序在数据库中存储了无效数据或者是由于流的逻辑中存在缺陷导致的。

消息流设计者必须认真对错误进行考虑,并确定如何处理这些错误。

使用缺省的错误处理

处理 ESQL 错误最简单的策略就是不执行任何操作并使用代理的缺省行为。缺省行为是中止失败消息的处理并继续处理下一条消息。输入节点和输出节点提供用于控制中止处理时将发生的具体情况的选项。

如果将输入节点和输出节点设置为事务方式,代理将恢复到处理消息之前的状态:
  1. 明显从输入队列获取的输入消息将被放回。
  2. 流明显写至输出队列的输出消息将被废弃。
如果没有将输入节点和输出节点设置为事务方式,则:
  1. 从输入队列获取的输入消息不会被放回。
  2. 流写至输出队列的任何输出消息都保留在该处。

这些策略中的每一个都具有其优势。事务方式保留数据的一致性,而非事务方式则能最大限度地连续处理消息。请记住,在事务方式中,失败的输入消息被放回到输入队列,代理将再次尝试处理它。此方式最可能的结果是,消息持续失败,直到达到重试限制,此时消息被放入死信队列。处理消息失败的原因被记录到系统事件日志(Windows)或 syslog(UNIX)。因此,失败消息将使后续正常消息的处理有所延迟,然后代理将使它保持未处理的状态。

大多数数据库都以事务方式运行,这样当消息处理成功时,将落实对数据库表作出的所有更改,处理失败时则回滚这些更改,从而保持数据的完整性。此情况的一个例外是,当代理本身或数据库失败时。(例如,运行代理或数据库的机器的电源可能中断。)在这些情况下,有可能有些数据库中的更改落实了,其他一些数据库中的更改则没有落实;或者数据库更改将落实,而输入消息和输出消息则不会落实。如果您担心发生这些可能情况,则应该对流进行协调并针对这种工作方式配置所涉及的数据库。

使用定制错误处理

此处有一些关于创建定制错误处理程序的一般技巧:
  1. 如果您需要比缺省错误处理更好的方法,第一步就是使用处理程序(请参阅 DECLARE HANDLER 语句)。每个节点创建一个处理程序来拦截所有可能的异常(或者是尽可能多的所能预见的异常)。
  2. 如果已经拦截了某个错误,则错误处理程序可以使用任何适用的逻辑来处理它。或者,它可以使用 THROW 语句或节点来创建异常,该异常可以以较高的流逻辑处理,或甚至到达输入节点(导致事务回滚)。请参阅抛出异常
  3. 如果节点抛出的异常没有被处理程序捕获,则流将转向 failure 终端(如果连接了 failure 终端),或者按缺省错误处理方法处理(如果未连接 failure 终端)。

    使用 failure 终端捕获未处理的错误。 将简单逻辑流连接到 failure 终端。此逻辑流可能由数据库或计算节点组成,计算节点将日志记录写至数据库(可能包含消息的位流)或将记录写至事件日志。它还可能包含将消息写至特殊队列的输出节点。

    整个异常树将被传递到连接到 failure 终端的任何节点。(异常树在 ExceptionList 树结构中有所描述。)

  4. 错误处理程序负责在适当的位置(如系统事件日志)记录每个错误。

有关可以用来处理消息流中错误的选项的详细讨论,请参阅处理消息流中的错误。以下主题提供了您可执行的操作的示例:

编写代码以检测错误

以下部分假定代理检测错误。但是,极有可能流逻辑会检测错误。例如,编写流逻辑代码时,您可以使用:
  • IF 语句,特别插入这些语句来检测不应该发生的情况
  • CASE 表达式或语句的 ELSE 子句,来阻止执行不应该可能的代码
作为流逻辑检测错误的示例,请设想具有一定范围的可能整数值(指示消息的类型)的字段。在这种情况下,如果对于要到来的消息,此字段的值与任何已知消息类型都不相符,则对于将发生的事项听天由命不是个好做法。可能发生这种情况的一个情形是,系统被升级为支持额外类型的消息,但某一部分的系统还没有升级。

使用您自己的逻辑来处理无效的输入消息

语句构成上无效的输入消息(以及由于错误的消息格式信息而显示为无效的输入消息)很难处理,这是因为代理不知道该消息包含什么内容。很可能处理它们的最好的方法就是配置输入节点来完全解析和验证消息。

但是,请注意这仅适用于预定义的消息,即 MRM 或 IDOC。

如果以这种方法配置输入节点,则当无法成功解析输入消息时,可以保证以下内容:
  • 该输入消息永远不会从节点的正常 output 终端显现(它将转至 failure 终端)。
  • 该输入消息永远不会进入消息流的主要部分。
  • 该输入消息永远不会导致任何数据库更新。
  • 没有任何消息会写至任何输出队列。

要处理失败的消息,请将简单逻辑流连接至 failure 终端。

此策略的唯一缺点就是,如果常规流不要求对所有消息字段的访问权,则强制完成消息解析将会影响性能。

使用您自己的逻辑来处理数据库错误

数据库错误分为三种类别:
  1. 数据库根本不工作(例如,它脱机了)。
  2. 数据库在工作,但拒绝您的请求(例如,发生了锁定争用)。
  3. 数据库在工作,但您要求它执行的操作不可能实现(例如,从不存在的表进行读取)。

如果您需要比缺省错误处理更好的方法,第一步就是使用处理程序(请参阅 DECLARE HANDLER 语句)来拦截异常。处理程序可以从数据库返回的 SQL 语句确定故障的性质。

数据库不工作
如果数据库根本不工作,而它对消息处理是必需的,则您所能执行的操作可能不多。在这种情况下,处理程序确定了原因之后,可能会执行以下操作中的任何一项:
  • 使用 RESIGNAL 语句重新抛出原始错误,从而允许缺省错误处理程序接管。
  • 使用不同的数据库。
  • 将消息写至特殊的输出队列。

    然而,请小心使用这种类型的策略。因为处理程序将吸收异常,所以对其他数据库进行的任何更改或对队列进行的任何写入都将落实。

数据库拒绝请求
发生锁定争用时的情况类似于“数据库不工作”的情况。这是因为数据库将回退您对当前消息所作的全部数据库更改,而不只是失败的请求。因此,除非您确定这是唯一的更新,否则除可能记录错误并将消息传递到特殊队列之外,不太可能有任何比缺省错误处理更好的策略。
不可能的请求
数据库在工作,但您要求它执行的操作不可能实现,这种情况覆盖了各种各样的问题。
如示例中所述,如果数据库只是没有流所期望名称的表,则除有可能记录错误或将消息传递到特殊的队列之外,还是不太可能有任何比缺省错误处理更好的策略。
但也有可能成功处理许多其他错误。例如,尝试插入行可能会失败,因为已经有了这样一行而新行将是重复的。或者,尝试更新行可能会失败,因为没有这样的行(即未对任何行进行更新)。在这些情况下,处理程序可以合并您认为合适的任何逻辑。它可能会插入缺少的行或利用现有的行(可能会确保其中的值合适)。
注: 要将更新零行报告为错误,必须将节点属性“将警告作为错误处理”设置为 true。这不是缺省设置。

使用您自己的逻辑处理输出节点中的错误

更新开始发生在 MQ output 节点中的错误会在 SQL 语句中报告错误的性质并在 SQL native error 变量中给出其他信息。因此,如果您需要比缺省错误处理更好的方法,第一步就是使用处理程序(请参阅 DECLARE HANDLER 语句)来拦截异常。这种处理程序通常仅围绕单个 PROPAGATE 语句。更新结束

使用您自己的逻辑处理其他错误

除上面谈到的那些错误之外,还可能发生各种其他错误。例如,算术计算可能溢出、强制类型转换可能由于数据不合适而失败,或者对消息字段的访问可能由于类型约束而失败。代理提供两种编程策略,用于处理这些错误。
  1. 导致异常的错误,要么得到处理,要么留待回滚事务。
  2. 将失败记录为特殊的值,稍后进行测试。

在缺少类型约束的情况下,尝试访问不存在的消息字段将产生值 null。Null 值通过表达式传播,使结果为空。因此,无论表达式多么复杂,只要它不返回空值,您就可以知道它所需用来计算其结果的所有值都不为空。

强制类型转换表达式可以具有缺省子句。如果有缺省子句,强制类型转换会毫无动静地失败;它们只返回缺省值,而不抛出异常。缺省值可能是没有害处的数字(例如,对整数使用零),或者在上下文中明显无效的值(例如对客户号使用 -1)。Null 可能特别适用,因为它是一个不同于所有其他值的值,将通过表达式传播而没有任何屏蔽出错条件的可能性。

处理其他节点中的错误

在其他节点(即,PROPAGATE 语句的下游)中发生的异常可能会被处理程序以常规方式捕获。但如果以巧妙的方式处理这种错误,会造成这样一个特殊问题,当原始错误涉及另一个节点时,在处理该错误时很有可能涉及另一个节点(不一定是异常的发起方)。

为了帮助处理这些情况,数据库节点和计算节点具有四个新的终端,称为 out1out2out3out4。另外,已经将 PROPAGATE 语句的语法扩展为包含目标表达式、消息源和控制子句,以对这些额外的终端进行更多控制。

声明 | 商标 | 下载 | 书库 | 支持 | 反馈
Copyright IBM Corporation 1999, 2006 最后一次更新时间:2006/08/14
ac17140_