Google Code offered in: English - Español - 日本語 - 한국어 - Português - Pусский - 中文(简体) - 中文(繁體)
NDB is an experimental, innovative, and rapidly changing new feature for App Engine. Unfortunately, being on the bleeding edge means that we may make backwards-incompatible changes to NDB. We will inform the community when this feature is no longer experimental.
A transaction is an operation or set of operations that either
succeeds completely or fails completely. An application can perform
multiple operations and calculations in a single transaction.
Using the NDB asynchronous API,
an application can manage multiple
transactions simultaneously if they are independent.
The synchronous API offers a simplified API using the
ndb.transaction()
function.
The transaction()
function takes a callback
function that is executed in the context of the transaction.
This simple example acts as a transactional get-or-insert operation:
key = ndb.Key(Greeting, 'joe') def callback(): # 'key' here uses the key variable in the outer scope; # the callback function is a closure. ent = key.get() if ent is None: ent = Greeting(key=key, message='Hey Joe') ent.put() return ent ent = ndb.transaction(callback)
If the transaction "collides" with another, it fails; NDB automatically
retries such failed transactions a few times.
Thus, the callback function may be called multiple times if the transaction
is retried. There is a limit (default 3) to the number of retries
attempted; if the transaction still does not succeed, the transaction() call
raises TransactionFailedError
. You can change the retry
count by passing retries=N
to the
transaction()
call. A retry count of 0 means the transaction
is attempted once but not retried if it fails; a retry count of
N means that the transaction may be attempted a total of
N+1 times. Example:
ent = ndb.transaction(callback, retries=1) # Total of 2 tries
By default, a transaction can only work with entities in the same entity group (entities whose keys have the same "ancestor").
In transactions, only ancestor queries are allowed.
You can specify
cross-group ("XG") transactions
(which allow up to five entity groups), by passing
xg=True
:
ent = ndb.transaction(callback, xg=True)
If the transaction's callback function raises an exception,
the transaction is immediately aborted and the
transaction()
call re-raises the exception.
You can force a transaction to fail silently by raising the
ndb.Rollback
exception (the
transaction()
call returns None
in this case). There is no mechanism to force a retry.
Often you have a function that must be run inside a transaction.
The @transactional
decorator automatically runs the
decorated function inside a transaction, with the added twist that
if a transaction is already in effect, it doesn't start a new
transaction but just calls the function. For example:
@ndb.transactional def get_or_insert(keyname): key = ndb.Key(Greeting, keyname) ent = key.get() if ent is None: ent = Greeting(key=key, message='Hey Rodrigo') ent.put() return ent moraes = get_or_insert('rodrigo')
The @transactional
decorator does not support
passing a retry count or other options.
To test whether some code is running inside a transaction,
use the in_transaction()
function:
def maybe_run_in_transaction(func): if ndb.in_transaction(): return func() else: return transaction(func)