2.4.1 处理 NDB API 错误

抽象的

本节描述如何检测 NDB API 错误并将其映射到特定操作。

可以通过以下两种方式之一生成 NDB API 错误:

  • 定义操作时

  • 执行操作时

操作定义期间出现的错误。  操作定义期间生成的错误会导致调用的方法返回失败代码。实际错误可以通过检查相关 NdbOperation对象或操作的NdbTransaction 对象来确定。

操作执行期间出现错误。  在操作执行期间发生的错误会导致它们所属的事务被中止,除非 AO_IgnoreError为操作设置了中止选项。

默认情况下,读取操作使用 运行 AO_IgnoreError,写入操作使用 运行AbortOnError,但这可以由用户覆盖。当执行过程中的错误导致事务中止时,该execute()方法返回失败返回码。AO_IgnoreError如果由于在操作上设置 错误而被忽略 ,则该execute()方法返回成功代码,并且用户必须使用检查所有操作是否失败 NdbOperation::getNdbError()。因此,getNdbError() 通常应该检查的返回值,即使execute() 返回成功。如果客户端应用程序在执行期间不跟踪 NdbOperation对象, NdbTransaction::getNextCompletedOperation() 则可用于迭代它们。

您还应该知道,使用 NdbBlob可能会导致将额外的操作添加到已执行的批处理中。这意味着,当使用 迭代完成的操作时 getNextCompletedOperation(),您可能会遇到与NdbBlob 您的应用程序未定义的对象相关的操作。

笔记

LockMode其is CommittedRead不能为 的读取AbortOnError。在这种情况下,它总是 be IgnoreError

在出现特定于操作的错误的所有情况下,都会针对操作和关联的事务对象标记操作的执行错误。在一次 NdbTransaction::execute()调用中出现多个操作错误的地方,由于操作批处理和 的使用 AO_IgnoreError,只有第一个被标记为NdbTransaction 对象。其余错误仅针对相应的NdbOperation 对象进行记录。

也有可能在执行过程中发生错误——例如数据节点故障——这些错误是针对事务对象标记的,而不是 针对底层操作对象标记的。这是因为这些错误适用于整个事务,而不适用于事务中的个别操作。

出于这个原因,应用程序应该使用 NdbTransaction::getNdbError()as 第一种方法来确定 NdbTransaction::execute()调用是否失败。如果正在执行的批操作包括AO_IgnoreError设置了 abort 选项的操作,则可能有多个失败,应该使用 NdbOperation::getNdbError().

扫描和 BLOB 方法中的隐式 NdbTransaction::execute() 调用。  扫描操作的执行方式与其他操作相同,并且execute() 在方法内部也有隐式调用 NdbScanOperation::nextResult() 。当 NdbScanOperation::nextResult() 指示失败时(即,如果方法返回 -1),应检查事务对象是否有错误。NdbScanOperation也可能包含错误,但前提是错误不是特定于操作的 。

一些 blob 操作方法也有隐式内部 execute()调用,因此在这些点上可能会遇到操作执行失败。以下 NdbBlob方法可以生成隐式execute()调用;这意味着 如果它们返回错误代码 ,它们还需要检查NdbTransaction对象是否有错误:NdbTransaction::getNdbError()

  • setNull()

  • truncate()

  • readData()

  • writeData()

概括。  一般情况下,调用以下任一方法都可能在执行过程中出错(导致返回失败码):

如果发生这种情况, NdbTransaction::getNdbError() 应调用该方法来识别发生的第一个错误。当操作是批处理 IgnoreError的时候,批处理中有操作,事务中可能有多个操作出错。这些可以通过使用 NdbTransaction::getNextCompletedOperation() 迭代完成的操作集来找到,调用 NdbOperation::getNdbError()每个操作。

IgnoreError对要执行的一批操作中的任何操作设置 when 时,NdbTransaction::execute()即使实际发生了错误,该方法也会指示成功,只要这些错误都没有导致事务中止。要确定是否存在任何忽略的错误,应使用 来检查事务错误状态 NdbTransaction::getNdbError()只有这表明成功,您才能确定没有发生错误。如果此方法返回错误代码,并且操作是批处理的,那么您应该遍历所有已完成的操作以找到所有忽略错误的操作。

示例(伪代码)。  我们首先执行一个事务,该事务可能具有批处理操作以及混合AO_IgnoreErrorAbortOnError中止选项:

int execResult= NdbTransaction.execute(args);
笔记

有关 的数量和允许值 args,请参阅 NdbTransaction::execute()

接下来,因为AO_IgnoreError 操作错误不会影响 execResult——即返回的值execute()——我们检查交易中的错误:

NdbError err= NdbTransaction.getNdbError();

if (err.code != 0)
{

错误代码的非零值表示交易中出现了错误。这可能是由于以下任何情况造成的:

  • 导致事务中止的事务范围错误,例如数据节点故障

  • 导致事务中止的单个特定于操作的错误,例如违反约束

  • 单个特定于操作的忽略错误,例如未找到数据,但不会导致事务中止

  • 许多特定于操作的忽略错误中的第一个,例如批处理时未找到数据,不会导致事务中止

  • 许多特定于操作的忽略错误中的第一个,例如在中止操作错误(事务中止)之前找不到数据(批处理时)

   if (execResult != 0)
   {

交易已中止。在这种情况下处理错误的建议策略是测试事务错误状态并根据其值采取适当的操作:

      switch (err.status)
      {
        case value1:
          //  statement block handling value1 ...
        case value2:
          //  statement block handling value2 ...
          //  (etc. ...)
        case valueN:
          //  statement block handling valueN ...
      }

由于事务已中止,通常有必要迭代已完成的操作(如果有的话)并仅在出于报告目的希望这样做时才查找每个操作引发的错误。

   }
   else
   {

事务本身并没有中止,但一定有一个或多个被忽略的错误。在这种情况下,您应该遍历操作以确定发生了什么并相应地处理原因。

   }
}

处理 NdbScanOperation::nextResult() 返回-1,表示操作失败(省略操作成功的情况):

int nextrc= NdbScanOperation.nextResult(args);
笔记

有关 的数量和允许值 args,请参阅 NdbScanOperation::nextResult()

if (nextrc == -1)
{

首先,您应该检查 NdbScanOperation对象是否有任何错误:

  NdbError err= NdbScanOperation.getNdbError();

  if (err.code == 0)
  {

扫描操作没有发现错误;错误必须属于整个交易。

  }
    err= NdbTransaction.getNdbError();

现在您可以根据错误状态处理错误:

    switch (err.status)
    {
      case value1:
        //  statement block handling value1 ...
      case value2:
        //  statement block handling value2 ...
        //  (etc. ...)
      case valueN:
        //  statement block handling valueN ...
    }
}

有关 NDB API 错误分类和状态代码的信息,请参阅第 2.4.4 节,“NDB 错误分类”。虽然您不应该依赖 NDB API 应用程序中的特定错误代码或消息文本——因为错误代码和消息都会随时间发生变化——但检查错误代码和消息以帮助确定特定故障发生的原因可能很有用. 有关这些的更多信息,请参阅 第 2.4.2 节,“NDB 错误代码:按类型”。有关 NdbError可以从 NdbError对象中获取的信息类型的更多信息,请参阅 第 2.3.15 节,“NdbError 结构”