摘要
本节介绍如何检测 NDB API 错误并将它们映射到特定操作。
NDB API 错误可以通过以下两种方式生成
在定义操作时
在执行操作时
在操作定义期间发生的错误。在操作定义期间生成的错误会导致调用的方法返回失败代码。可以通过检查相关的 NdbOperation
对象或操作的 NdbTransaction
对象来确定实际错误。
在操作执行期间发生的错误。在操作执行期间发生的错误会导致包含这些错误的事务被中止,除非为该操作设置了 AO_IgnoreError
中止选项。
默认情况下,读取操作以 AO_IgnoreError
运行,而写入操作以 AbortOnError
运行,但用户可以覆盖此设置。当执行期间发生的错误导致事务中止时,execute()
方法将返回失败代码。如果由于在操作上设置了 AO_IgnoreError
而忽略了错误,则 execute()
方法将返回成功代码,并且用户必须使用 NdbOperation::getNdbError()
检查所有操作是否失败。因此,即使 execute()
返回成功,也应该通常检查 getNdbError()
的返回值。如果客户端应用程序在执行期间没有跟踪 NdbOperation
对象,则可以使用 NdbTransaction::getNextCompletedOperation()
来迭代它们。
您还应该注意,使用 NdbBlob
会导致在执行的批次中添加额外的操作。这意味着,当使用 getNextCompletedOperation()
迭代已完成的操作时,您可能会遇到与您的应用程序未定义的 NdbBlob
对象相关的操作。
其 LockMode
为 CommittedRead
的读取不能为 AbortOnError
。在这种情况下,它始终为 IgnoreError
。
在所有出现操作特定错误的情况下,都会在操作和相关事务对象上标记一个包含操作的执行错误。如果在单个 NdbTransaction::execute()
调用中存在多个操作错误,这是由于操作批处理和使用 AO_IgnoreError
造成的,则只会在 NdbTransaction
对象上标记第一个错误。其余错误只记录在相应的 NdbOperation
对象上。
在执行期间,还可能发生错误,例如数据节点故障,这些错误会在事务对象上标记,但不会在底层操作对象上标记。这是因为这些错误适用于整个事务,而不适用于事务中的各个操作。
因此,应用程序应使用 NdbTransaction::getNdbError()
作为确定 NdbTransaction::execute()
调用是否失败的第一种方法。如果正在执行的操作批次包含设置了 AO_IgnoreError
中止选项的操作,则可能存在多个操作错误,应使用 NdbTransaction::getNextCompletedOperation()
迭代已完成的操作集,并为每个操作调用 NdbOperation::getNdbError()
。
扫描和 BLOB 方法中的隐式 NdbTransaction::execute() 调用。扫描操作与其他操作以相同的方式执行,并且在 NdbScanOperation::nextResult()
方法中也有隐式 execute()
调用。当 NdbScanOperation::nextResult()
指示失败(即,如果方法返回 -1
)时,应检查事务对象是否有错误。 NdbScanOperation
也可能包含错误,但前提是错误不是操作特定的。
某些 blob 操作方法也有隐式内部 execute()
调用,因此在这些点可能会遇到操作执行失败。以下 NdbBlob
方法可以生成隐式 execute()
调用;这意味着它们也需要检查 NdbTransaction
对象是否有错误,方法是使用 NdbTransaction::getNdbError()
,如果它们返回错误代码
setNull()
truncate()
readData()
writeData()
总结。通常,在调用以下任何方法时,都可能在执行期间发生错误(导致返回失败代码)
-
NdbScanOperation::nextResult()
注意此方法不执行隐式
execute()
调用。NdbBlob
方法可能会在调用这些方法时导致执行其他已定义的操作;但是,nextResult()
调用不会这样做。
如果发生这种情况,则应调用 NdbTransaction::getNdbError()
方法来识别发生的第一个错误。当操作被批处理并且批次中存在 IgnoreError
操作时,事务中可能存在多个包含错误的操作。可以通过使用 NdbTransaction::getNextCompletedOperation()
迭代已完成的操作集,并为每个操作调用 NdbOperation::getNdbError()
来找到这些错误。
当在一批要执行的操作中,任何操作都设置了 IgnoreError
时,即使实际上发生了错误,只要这些错误没有导致事务中止,NdbTransaction::execute()
方法也会指示成功。要确定是否发生了任何被忽略的错误,应使用 NdbTransaction::getNdbError()
检查事务错误状态。 只有当此方法指示成功时,您才能确定没有发生错误。如果此方法返回错误代码,并且操作已批处理,则应遍历所有已完成的操作以查找所有具有被忽略错误的操作。
示例 (伪代码). 我们首先执行一个事务,该事务可能包含批处理操作以及 AO_IgnoreError
和 AbortOnError
中止选项的混合。
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
{
事务本身未中止,但必须存在一个或多个被忽略的错误。在这种情况下,您应该遍历操作以确定发生了什么情况,并相应地处理原因。
}
}
要处理返回 -1
的 NdbScanOperation::nextResult()
,表示操作失败(省略操作成功的情况)
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 结构”。