views:

106

answers:

4

I know that the way to handle DB transactionality on the app engine is to give different entities the same Parent(Entity Group) and to use db.run_in_transaction.

However, assume that I am not able to give two entities the same parent. How do I ensure that my DB updates occur in a transaction?

Is there a technical solution? If not, is there a pattern that I can apply?

Note: I am using Python.

+5  A: 

As long as the entities belong to the same Group, this is not an issue. From the docs:

All datastore operations in a transaction must operate on entities in the same entity group. This includes querying for entities by ancestor, retrieving entities by key, updating entities, and deleting entities. Notice that each root entity belongs to a separate entity group, so a single transaction cannot create or operate on more than one root entity. For an explanation of entity groups, see Keys and Entity Groups.

There is also a nice article about Transaction Isolation in App Engine.

EDIT: If you need to update entities with different parents in the same transaction, you will need to implement a way to serialize the changes that were made by yourself and rollback manually if an exception is raised.

jbochi
But if you follow the "Keys and Entity Groups" link to http://code.google.com/appengine/docs/python/datastore/keysandentitygroups.html#Entity_Groups_Ancestors_and_Paths, the only method listed for putting two Entities in the same Entity Group is to make sure they share an ancestor
James Polley
Sorry, suppose technically I mean Groups, not parents. But yes, according to the book I'm reading it appears that the only way to assign groups in python is through a common ancestor/parent.
willem
@James @Willem You are both right. Entities are considered a group only if they share the same root/parent node. I have edit my answer.
jbochi
Sounds like I am out of luck then. I will have to build custom transaction handling code, or alter my domain so entities can belong to the same group. I think the latter option is simpler (but uglier).
willem
+1  A: 

Transactions in the AppEngine datastore act differently to the transactions you might be used to in an SQL database. For one thing, the transaction doesn't actually lock the entities it's operating on.

The Translation Isolation in App Engine article explains this in more detail.

Because of this, you'll want to think differently about transactions - you'll probably find that in most of the cases where you're wanting to use a transaction it's either unnecessary - or it wouldn't achieve what you want.

For more information about entity groups and the data store model, see How Entities and Indexes are Stored.

Handling Datastore Errors talks about things that could cause a transaction to not be committed and how to handle the problems.

James Polley
+1  A: 

One possibility is to implement your own transaction handling as you have mentioned. If you are thinking about doing this, it would be worth your time to explore the previous work on this problem.

http://danielwilkerson.com/dist-trans-gae.html

Dan Wilkerson also gave a talk on it at Google IO. You should be able to find a video of the talk.

Kris Walker
Very useful, thanks Kris.
willem
+2  A: 

If you want cross-entity-group transactions, you'll have to implement them yourself, or wait for a library to do them. I wrote an article a while ago about how to implement cross-entity-group transactions in the 'bank transfer' case; it may apply to your use-case too.

Nick Johnson
+1 very nice article! thank you!
jbochi