Skip to content

Latest commit

 

History

History
303 lines (236 loc) · 11 KB

Transactions.wiki

File metadata and controls

303 lines (236 loc) · 11 KB

  1. summary Transactions
Transactions are where Objectify departs most significantly from the patterns set by the Low-Level API and JDO/JPA. Objectify's transactions are inspired by EJB and NDB transactions: Designed to allow modular, convenient transactional logic with a minimum of boilerplate.

You should familiarize yourself with the GAE Transactions documentation.

Table of Contents

Basic Transactions

A basic transaction looks like this:

Note that all pending async operations are automatically completed at the end of a transaction.

Idempotence

  • Work MUST be idempotent.* A variety of conditions, including , can cause a transaction to retry. If you need to limit the number of times a transaction can be tried, use .

Cross-Group Transactions

Objectify requires no special flags to enable cross-group transactions. If you access more than one entity group in a transaction, the transaction with be an XG transaction. If you do access only one, it is not. The standard limit of 5 EGs applies to all transactions.

Transaction Inheritance

Transaction contexts are inherited. In this example, the inner does *not* start a new transaction:

This makes it easy to create modular bits of transactional logic that can be used from a variety of contexts without having to pass around instances as parameters.

If you need to suspend a transaction and begin a new one, use the method:

The old transaction (if present) is suspended for the duration of the new transaction. After the transaction commits (or rolls back), the original transaction will resume.

Escaping Transactions

There are often times in the middle of a transaction when you would like to make a datastore request outside of a transaction. Perhaps you wish to make a query without an ancestor(), or perhaps you wish to load an entity without enlisting it in a XG transaction.

Objectify makes it easy to run operations outside of a transaction:

This circumstance doesn't come up often but it does come up.

Transactions and Caching

Starting a transaction creates a new instance with a fresh, empty session cache. Loads and saves will populate this new instance cache; because of this, entities modified will appear modified after being loaded again within the same transaction. Unlike the low-level API, the datastore will not appear "frozen in time", although transaction isolation is maintained.

When a transaction successfully commits, its session cache will be copied into the parent instance's session cache.

Transactions integrate correctly with Objectify's global memcache. Reads and writes bypass the memcache, but a successful commit will reset the memcache value for changed entities.

execute()

Objectify provides a method designed to facilitate EJB-like behavior:

The enum provides the common EJB transaction attributes:

|| MANDATORY || If not already in a transaction, throw an exception. Otherwise, use the transaction. || || REQUIRED || If there is already a transaction in progress, use it. If not, start a new transaction. || || REQUIRES_NEW || If there is already a transaction in progress, suspend it. Always start a new transaction. || || SUPPORTS || If there is a transaction in progress, use it. Otherwise, execute without a transaction. || || NOT_SUPPORTED || If there is a transaction in progress, suspend it. Execute without a transaction. || || NEVER || If there is a transaction in progress, throw an exception. Otherwise, execute without a transaction. ||

You will probably not use this method directly. However, you can easily use it to build AOP interceptors for Guice and Spring.

Transactions with Guice

Using Guice AOP you can place EJB-like annotations on methods and eliminate all the } boilerplate:

These methods are automatically wrapped in classes and executed with .

This requires two classes:

Now, to enable this interceptor, add this to your Guice module configuration:

You can find a working example of this in the Motomapia sample application.

Transactions with Spring

With Spring AOP transaction management can be implemented as a cross-cutting _aspect_ to be applied to point-cuts in the application.

Imagine you have the following test worker, for which you want all methods to run in a transaction:

When injecting the bean:

For every method call, either a separate transaction should be opened or the preexisting transactional context should be inherited:

To achieve this, two things need to be done: firstly, one has to implement an _around advice_ in order to wrap every method invocation in a instance and execute it with :

Secondly, one has to declare the _aspect_ with the _around advice_ in the Spring configuration:

A working prototype can be found here: https://github.com/dajudge/appengine-objectify-spring-transactions-example