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代表總共會嘗試交易「N+1」N次。範例: <0

@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