Manualy Execute Code in Transaction in Test with Rollback

we are using spring boot 2, and in our integration tests we need manually execute some code in transaction, and on the end of transaction and after asserts, we want rollback that transaction.

We are using explicit defined transactions instead of @Transactional because sometimes we need execute in test 2 transactions.

here is sample of test:

@Test
public void fooTest() {

    // transaction 1
    transactionTemplate.execute(new TransactionCallbackWithoutResult() {
        @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                // some code in transaction
            }

    // transaction 2
    transactionTemplate.execute(new TransactionCallbackWithoutResult() {
        @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                // some code in transaction
            }

    // here I need rollback these transactions for clean db for another tests
}

can you tell me how to use rollback in our case to rollback both transactions? It is little older code which we maintain so if it possible to do it better in boot 2 I will be gratefull for any advice. We just have to execute 2 transactions in one test.

3

2 Answers

Store references to each TransactionStatus in AtomicReference and rollback them with transaction manager after the test.

@Test
void test() {
  final AtomicReference<TransactionStatus> first = new AtomicReference<>();
  final AtomicReference<TransactionStatus> second = new AtomicReference<>();
  transactionTemplate.execute(new TransactionCallbackWithoutResult() {
    @Override
    protected void doInTransactionWithoutResult(TransactionStatus status) {
      // some code in transaction
      first.set(status);
    }
  });

  // transaction 2
  transactionTemplate.execute(new TransactionCallbackWithoutResult() {
    @Override
    protected void doInTransactionWithoutResult(TransactionStatus status) {
      // some code in transaction
      second.set(status);
    }
  });
  transactionTemplate.getTransactionManager().rollback(first.get());
  transactionTemplate.getTransactionManager().rollback(second.get());
}
1

If you really need to start two transactions that run independently, doing some work on each one, and you need to check some asserts after they have both run, but before either has committed or rolled back - and then need to commit or rollback both after the asserts, you would need to set up your own multithreaded structure... Something like:

execute(AssertCallback aC, TransactionCallback ... tCs);

This method would start a thread for each of the tCs. Each thread would call the callback method in each one, and on return block on a barrier until all the threads executing tCs get to that same point. The main thread would also be waiting for all the tC threads to block, and then it would run the aC callback, and when that returns, release all the tC threads so they can commit/rollback and exit.

It all seems a little weird, in that the aC callback could not "see" any of the work done by any of the tC callbacks, since that's in transactions that have not been committed yet.

I've never seen this implemented... But, in case you want to see what I was talking about, take a look at the parallel-test project here:

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Sophia Al-Mansoor

Sophia Al-Mansoor

Global Business & E-Commerce Reporter

Sophia analyzes international trade, startup ecosystems, retail transformation, and supply chain logistics for modern digital publications.

Share this article
Twitter Facebook Pinterest