When coding a Spring application, we will typically be annotating our service methods with @Tansactional, and sometimes we would want to execute come code only if the transaction succeeds. For example, when a user signs up, she should receive a verification mail only if her record is successfully committed to the database.

Precisely, a signup process can flow as below:

  1. Our signup controller receives a signup request
  2. It calls a service method for doing the job
  3. A transaction begins
  4. The service method
    1. saves the new user to the database
    2. sends a verification mail to the user
    3. exits
  5. The transaction tries to commit, FAILS for some reason, and rolls back!
  6. The controller receives the exception and passes it to the client
  7. The user sees that she was unable to sign up
  8. She still gets a verification mail!

Actually, we should execute 4.2 only if the transaction succeeds. Otherwise the user will get a verification mail even if the signup fails!

A way to tell Spring to run such code only after the transaction succeeds is to put the code in the afterCommit method of a TransactionSynchronizationAdapter object, and register the object.

Precisely, we should code 4.2 like this:

TransactionSynchronizationManager.registerSynchronization(
    new TransactionSynchronizationAdapter() {
        @Override
        public void afterCommit() {
            // code for sending verification mail
        }
});

This is heavy boilerplate code. Using Java 8, we can encapsulate it into a utility method, as below:

public static void afterCommit(Runnable runnable) {
    TransactionSynchronizationManager.registerSynchronization(
        new TransactionSynchronizationAdapter() {
            @Override
            public void afterCommit() {
                runnable.run();
            }
    });
}

afterCommit can then be used as below:

afterCommit(() -> {
    // code for sending verification mail
});

If you found it helpful, you may like our Spring Framework Tutorials, which cover such essential real-world use cases in details!