The objectify documentation states this about transactions:
Work MUST be idempotent. A variety of conditions, including ConcurrentModificationException, can cause a transaction to retry. If you need to limit the number of times a transaction can be tried, use transactNew(int, Work).
However, the google datastore documentation states:
The Datastore API does not automatically retry transactions, but you can add your own logic to retry them, for instance to handle conflicts when another request updates the same entity at the same time.
These statements seem contradictory. Are objectify transactions really retried? Just to be safe I am using transactNew(1, Work)
to make sure it runs only once, but what is going on under the hood and why?
The google documentation states that one use of transactions is to do things like transfer money from one account to another. If transactions are retrying then that would not work because by nature transferring money is not idempotent. In this case, using transactNew(1, Work)
is the correct thing to do right? Basically, I am looking to do a non-idempotent transaction safely.
Objectify will retry on CME. There is some question as to whether you can get a CME when the transaction actually commits - once upon a time it was documented that this was possible, but Google may have eliminated that.
Nevertheless, the "right way" to ensure a (say) bank transfer completes is not to limit the retries.
This ends up being pretty much standard behavior for any bank-like ledger; you create a transaction record along with the debit+credit. If you create a transaction record, it is easy to enforce idempotence.