摘要
本節說明如何偵測 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
中止選項的操作,則可能有多個失敗,應該使用 NdbOperation::getNdbError()
個別檢查已完成的操作是否有錯誤。
掃描與 BLOB 方法中的隱含 NdbTransaction::execute() 呼叫。掃描操作的執行方式與其他操作相同,並且在 NdbScanOperation::nextResult()
方法中也有隱含的 execute()
呼叫。當 NdbScanOperation::nextResult()
指示失敗時(也就是說,如果方法傳回 -1
),應該檢查交易物件是否有錯誤。NdbScanOperation
也可能包含錯誤,但前提是該錯誤不是特定於操作的錯誤。
某些 blob 操作方法也有隱含的內部 execute()
呼叫,因此可能會在這些點發生操作執行失敗。以下 NdbBlob
方法可以產生隱含的 execute()
呼叫;這表示如果它們傳回錯誤碼,也需要透過 NdbTransaction::getNdbError()
檢查 NdbTransaction
物件是否有錯誤
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 結構」。