Creating a post commit when using transaction in Spring

Since Spring 4.2 it has been possible to define listeners for post commit events (or more generally transaction synchronization events e.g. rollbacks) using annotation based configuraton. This is based off event handling in core spring. It is easier to test code using this approach since you avoid a direct dependency on TransactionSynchronizationManager, which will likely not be active in a unit test. You can easily test that your transactional service publishes an event and also that your listener performs the right action when you receive an event.

So without further ado this is how to set it up:

In this example we'll assume you have a Customer entity and a CustomerRepository (and ORM to go with it).

First you need a new event type NewCustomerEvent:

// NewCustomerEvent.java
// Just a regular pojo for the event
public class NewCustomerEvent {

    public String email;

    // constructor, setters and getters omitted
}

Then you define a listener using @TransactionalEventListener. By default this will execute after a sucessful commit but this can be changed using the phase parameter:

// NewCustomerEventListener.java
@Component
public class NewCustomerEventListener {

    @TransactionalEventListener
    public void handleNewCustomerEvent(NewCustomerEvent newCustomerEvent) {
        // handle new customer event
    }
}

Finally you augment your transaction service with an ApplicationEventPublisher on which you call publish once all the transaction statements have been sent.

// CustomerRespositoryService.java
@Service
public class CustomerRepositoryService {

    @Inject
    private ApplicationEventPublisher applicationEventPublisher;

    @Inject
    private CustomerRepository customerRepository;

    @Transactional
    public void createCustomer(String email) {
        Customer customer = new Customer(email);
        customerRespotory.save(customer);
        applicationEventPublisher.publish(new NewCustomerEvent(email));
    }

}

See also:

  • https://dzone.com/articles/simpler-handling-of-asynchronous-transaction-bound
  • https://dzone.com/articles/transaction-synchronization-and-spring-application

Credit to Grooveek's answer and Alex's comment under it - I put this here because the combined suggestions provide a solid and cleaner solution that is hard to find around the net.

Using Spring 4+. if you need a callback on a @Transactional method after it successfully commits just add that in the beginning of the method:

@Service
public class OneService {

    @Autowired
    OneDao dao;

    @Transactional
    public void a transactionalMethod() {
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter(){
            public void afterCommit(){
                //do stuff right after commit
                System.out.println("commit!!!");

            }
        });
        //do db stuff
        dao.save();
    }
}

You could get exactly what you want by a simpler way, with TransactionSynchronizationManager and TransactionSynchronization

With TransactionSynchronizationManager, you have static methods to get information about current transaction, and you can register a TransactionSynchronization wich allows you to automatically do a post-commit as you call that

TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization(){
           void afterCommit(){
                //do what you want to do after commit
           }
})

Be aware that the TransactionSynchronization is on a per-thread basis (which is often not a problem for a basic web request).