NDB 交易

交易是指一項或一組不可分割的作業,這代表交易絕不會只有部分執行;交易中的所有作業不是全部執行,就是全部不執行。交易的最長持續時間為 60 秒,而在 30 秒後則有 10 秒的閒置到期時間。

使用 NDB 非同步 API 時,應用程式可以同時管理多筆獨立的交易。同步 API 會使用 @ndb.transactional() 修飾符提供簡化的 API。經過修飾的函式會在交易背景中執行。

@ndb.transactional
def insert_if_absent(note_key, note):
    fetch = note_key.get()
    if fetch is None:
        note.put()
        return True
    return False
note_key = ndb.Key(Note, note_title, parent=parent)
note = Note(key=note_key, content=note_text)
inserted = insert_if_absent(note_key, note)

如果交易與其他交易「衝突」,就會失敗;NDB 會自動重試這類失敗的交易幾次。如果重試交易,系統可能會多次呼叫此函式。嘗試的重試次數設有限制 (預設為 3 次)。如果交易仍未成功,NDB 會傳回 TransactionFailedError。您可以將 retries=N 傳遞至 transactional() 修飾符,藉此變更重試次數。重試次數為 0 代表會嘗試交易一次,失敗就不會重試;重試次數為 N 代表總共會嘗試交易 N+1 次。範例:

@ndb.transactional(retries=1)
def insert_if_absent_2_retries(note_key, note):
    # do insert

在交易中,系統只允許祖系查詢。根據預設,交易僅適用於相同實體群組的實體 (具有相同「祖系」的金鑰)。

您可以傳送 xg=True 來指定跨群組 (「XG」) 交易 (最多可允許二十五個實體群組):

@ndb.transactional(xg=True)
def insert_if_absent_xg(note_key, note):
    # do insert

跨群組交易會跨多個實體群組運作,並且會像單一群組交易一樣運作,但如果程式碼嘗試更新多個實體群組中的實體,則不會失敗。

如果函式擲回例外狀況,交易會立即中止,且 NDB 會重新擲回例外狀況,讓呼叫程式碼看到該例外狀況。您可以引發 ndb.Rollback 例外狀況 (在這個情況下,函式呼叫會傳回 None),藉此強制交易失敗而不顯示任何訊息。沒有強制重試的機制。

您可能會有不想在交易中執行的函式。請不要使用 @ndb.transactional 修飾這類函式,而是將其做為回呼函式傳送至 ndb.transaction()

def insert_if_absent_sometimes(note_key, note):
    # do insert
inserted = ndb.transaction(lambda:
                           insert_if_absent_sometimes(note_key, note))

如要測試特定程式碼是否在交易中執行,請使用 in_transaction() 函式。

您可以指定「交易」函式在受到交易中已存在程式碼叫用時的行為。@ndb.non_transactional 修飾符會指定函式不應在交易中執行;如果在交易中呼叫,則會在交易外執行。@ndb.transactional 裝飾器和 ndb.transaction 函式會使用 propagation 關鍵字引數。舉例來說,如果函式應啟動新的獨立交易,請依此裝飾函式:

@ndb.transactional(propagation=ndb.TransactionOptions.INDEPENDENT)
def insert_if_absent_indep(note_key, note):
    # do insert

傳播類型會與其他內容選項和交易選項一併列出

如果您沒有明確掌握目前的狀況,交易行為以及 NDB 的快取行為可能會讓您感到混淆。如果您在交易中修改實體,但尚未提交交易,則 NDB 的內容快取會包含已修改的值,但基礎資料儲存庫仍會保留未修改的值。

交易工作排入佇列

您可以將工作排入佇列做為資料儲存庫交易的一部分,以便只在成功修訂交易時才將工作排入佇列。如未修訂交易,則工作不會排入佇列。如已確實修訂交易,工作就會排入佇列。排入佇列後,工作不會立即執行,因此工作與交易並非不可分割。不過,將工作排入佇列後,該工作將不斷重試直到成功為止。這適用於在經過修飾的函式中排入佇列的任何工作。

您可以透過交易工作,將非資料儲存庫的動作結合至依賴交易成功的交易 (例如傳送電子郵件以確認購買),因此非常實用。您也可以將 Datastore 動作繫結至交易,例如在交易成功時,將交易以外的實體群組變更提交至交易。

在單一交易期間,應用程式最多只能將五項交易工作插入工作佇列。交易工作不得有使用者指定的名稱。

from google.appengine.api import taskqueue
from google.appengine.ext import ndb
@ndb.transactional
def insert_if_absent_taskq(note_key, note):
    taskqueue.add(url=flask.url_for('taskq_worker'), transactional=True)
    # do insert