Savepoint

Ebean supports using Savepoints which are a feature of most Relational Databases in which we can create a Savepoint (nested transaction) inside a transaction which can commit or rollback as a unit of work.

If we have a task that performs some operations which can fail/rollback, but don't want to loose all the work for the entire transaction Savepoint provides a mechanism to do this. You can check more information on Oracle's JDBC tutorial

Transaction.setNestedUseSavepoint()

For a transaction we can use transaction.setNestedUseSavepoint() to enable it to use Savepoint for nested transactions. This means that these nested transactions can be rolled back leaving the outer transaction to continue and potentially commit.

Example
// start 'outer' transaction
try (Transaction outerTxn = database.beginTransaction()) {

  outerTxn.setNestedUseSavepoint();

  // do stuff with the 'outer' transaction
  bean.save();

  try (Transaction nestedTransaction = database.beginTransaction()) {
    // nested transaction is a savepoint ...

    // do some piece of work which we might want to either commit or rollback ...
    otherBean.save();

    if (...) {
      nestedTransaction.rollback();

    } else {
      nestedTransaction.commit();
    }
  }

  // continue using 'outer' transaction ...

  outerTxn.commit();
}

Explicit Savepoints

As an alternative to using transaction.setNestedUseSavepoint() we can instead explicitly create and use savepoints by obtaining the JDBC Connection from the transaction.

For example:

var newCustomer = new Customer();
newCustomer.setName("John");
newCustomer.save();

try (Transaction transaction = DB.beginTransaction()) {

  Connection connection = transaction.getConnection();

  // create a Savepoint
  Savepoint savepoint = connection.setSavepoint();

  newCustomer.setName("Doe");
  newCustomer.save();

  // Rollback to a specific save point
  connection.rollback(savepoint);
  transaction.commit();
}

var found = DB.find(Customer.class, newCustomer.getId());
System.out.println(found.getName()); // Prints "John"