We have a problem in a Spring Boot app where some files are created during a database transaction and they need to be deleted if the transaction rolls back. This is my solution...
When a file is created, we publish an event containing the filename:
applicationEventPublisher.publishEvent(new FileCreatedEvent(this, filename));
We have another component which listens for the event:
@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void handleRollback(FileCreatedEvent event) {
fileDeleter.delete(event.getFilename());
}
As you can see, Spring Framework provides a pub/sub event management feature where you can publish an event using ApplicationEventPublisher (which can easily be autowired). You can then subscribe to the event using a @TransactionalEventListener annotation ^1, which can be tailored to fire only after a rollback by setting the phase parameter on the annotation to AFTER_ROLLBACK (as shown).
Crucially, the events are not delivered to the listener until the transaction resolves. This makes logic around transactions much simpler.Also, this works with multiple simultaneous events attached to the same transaction, which means you can fire discrete events for each file and the events will each be delivered when the transaction completes.
One other potential use for this pattern would be to prevent misleading log/audit entries by triggering an event for a new entry but only recording the event if and when the transaction commits successfully. This way you wouldn't see log messages saying "created new entity in database" unless the new entity had really been created.
^1 This pattern also works without transactions if you subscribe using a simple @EventListener. In this case, the event would be handled immediately by the listener, rather than waiting until the end of the transaction.
Top comments (0)