Python

0.02.2

Transactions#

Create / interact with gcloud datastore transactions.

class gcloud.datastore.transaction.Transaction(dataset)[source]#

Bases: object

An abstraction representing datastore Transactions.

Transactions can be used to build up a bulk mutuation as well as provide isolation.

For example, the following snippet of code will put the two save operations (either insert_auto_id or upsert) into the same mutation, and execute those within a transaction:

>>> from gcloud import datastore
>>> dataset = datastore.get_dataset('dataset-id', email, key_path)
>>> with dataset.transaction(bulk_mutation=True)  # The default.
...   entity1.save()
...   entity2.save()

By default, the transaction is rolled back if the transaction block exits with an error:

>>> from gcloud import datastore
>>> dataset = datastore.get_dataset('dataset-id', email, key_path)
>>> with dataset.transaction() as t:
...   do_some_work()
...   raise Exception() # rolls back

If the transaction block exists without an exception, it will commit by default.

Warning

Inside a transaction, automatically assigned IDs for entities will not be available at save time! That means, if you try:

>>> with dataset.transaction():
...   entity = dataset.entity('Thing').save()

entity won’t have a complete Key until the transaction is committed.

Once you exit the transaction (or call commit()), the automatically generated ID will be assigned to the entity:

>>> with dataset.transaction():
...   entity = dataset.entity('Thing')
...   entity.save()
...   assert entity.key().is_partial()  # There is no ID on this key.
>>> assert not entity.key().is_partial()  # There *is* an ID.

Warning

If you’re using the automatically generated ID functionality, it’s important that you only use gcloud.datastore.entity.Entity.save() rather than using gcloud.datastore.connection.Connection.save_entity() directly.

If you mix the two, the results will have extra IDs generated and it could jumble things up.

If you don’t want to use the context manager you can initialize a transaction manually:

>>> transaction = dataset.transaction()
>>> transaction.begin()

>>> entity = dataset.entity('Thing')
>>> entity.save()

>>> if error:
...   transaction.rollback()
... else:
...   transaction.commit()

For now, this library will enforce a rule of one transaction per connection. That is, If you want to work with two transactions at the same time (for whatever reason), that must happen over two separate gcloud.datastore.connection.Connection s.

For example, this is perfectly valid:

>>> from gcloud import datastore
>>> dataset = datastore.get_dataset('dataset-id', email, key_path)
>>> with dataset.transaction():
...   dataset.entity('Thing').save()

However, this wouldn’t be acceptable:

>>> from gcloud import datastore
>>> dataset = datastore.get_dataset('dataset-id', email, key_path)
>>> with dataset.transaction():
...   dataset.entity('Thing').save()
...   with dataset.transaction():
...     dataset.entity('Thing').save()

Technically, it looks like the Protobuf API supports this type of pattern, however it makes the code particularly messy. If you really need to nest transactions, try:

>>> from gcloud import datastore
>>> dataset1 = datastore.get_dataset('dataset-id', email, key_path)
>>> dataset2 = datastore.get_dataset('dataset-id', email, key_path)
>>> with dataset1.transaction():
...   dataset1.entity('Thing').save()
...   with dataset2.transaction():
...     dataset2.entity('Thing').save()
Parameters:dataset (gcloud.datastore.dataset.Dataset) – The dataset to which this Transaction belongs.
add_auto_id_entity(entity)[source]#

Adds an entity to the list of entities to update with IDs.

When an entity has a partial key, calling save() adds an insert_auto_id entry in the mutation. In order to make sure we update the Entity once the transaction is committed, we need to keep track of which entities to update (and the order is important).

When you call save() on an entity inside a transaction, if the entity has a partial key, it adds itself to the list of entities to be updated once the transaction is committed by calling this method.

begin()[source]#

Begins a transaction.

This method is called automatically when entering a with statement, however it can be called explicitly if you don’t want to use a context manager.

commit()[source]#

Commits the transaction.

This is called automatically upon exiting a with statement, however it can be called explicitly if you don’t want to use a context manager.

This method has necessary side-effects:

  • Sets the current connection’s transaction reference to None.
  • Sets the current transaction’s ID to None.
  • Updates paths for any keys that needed an automatically generated ID.
connection()[source]#

Getter for current connection over which the transaction will run.

Return type:gcloud.datastore.connection.Connection
Returns:The connection over which the transaction will run.
dataset()[source]#

Getter for the current dataset.

Return type:gcloud.datastore.dataset.Dataset
Returns:The dataset to which the transaction belongs.
id()[source]#

Getter for the transaction ID.

Return type:string
Returns:The ID of the current transaction.
mutation()[source]#

Getter for the current mutation.

Every transaction is committed with a single Mutation representing the ‘work’ to be done as part of the transaction. Inside a transaction, calling save() on an entity builds up the mutation. This getter returns the Mutation protobuf that has been built-up so far.

Return type:gcloud.datastore.datastore_v1_pb2.Mutation
Returns:The Mutation protobuf to be sent in the commit request.
rollback()[source]#

Rolls back the current transaction.

This method has necessary side-effects:

  • Sets the current connection’s transaction reference to None.
  • Sets the current transaction’s ID to None.