JdbcAccess: Defer exceptions when in a transaction

The insert/update/delete methods may throw OrmExceptions immediately
when a primary key constraint is violated or when attempting to modify
a row that does not exist. This violates the expectations of callers
who assume that no work is actually done until the transaction is
committed. Work around this in the simplest way possible, by holding
on to the first exception encountered during a transaction and
throwing it immediately from commit().

This enables a pattern where callers can "turn off" database access
entirely by always using transactions and simply never committing
them:

  db.table().beginTransaction(key);
  try {
    db.table().insert(foo);
    if (dbIsEnabled) {
      db.commit();
    }
  } finally {
    db.rollback();
  }

  db.table().beginTransaction(key);
  try {
    db.table().delete(foo.getKey());
    if (dbIsEnabled) {
      db.commit();
    }
  } finally {
    db.rollback();
  }

The problem with this pattern, prior to this change, is that if the
first transaction never inserted foo, then the delete call will
immediately throw OrmConcurrencyException due to foo's key not
existing.

Change-Id: Ic7ced328a4d3659cb8b7b00cb387142dbf8a0522
5 files changed