Execute before or after a spring transactional method
Spring provides a mechanism through which you can plugin some code which gets executed after the transaction is complete. We need to provide an implementation of the org.springframework.transaction.support.TransactionSynchronization interface which can be registered using TransactionSynchronizationManager. This could be useful in scenario where your code does not have a control over when the transaction starts and ends. For e.g. Your service code always joins an existing transaction started by the calling method (using REQUIRED PROPAGATION LEVEL).
Lets have a look at some sample code. Below sample captures one of the bulk report upload use case where each record in a database has a corresponding report (physical file). When the existing records are replaced with new records their corresponding reports would have to be deleted after the transaction successfully commits.
public class ServiceBean { @Transactional public void copyNewRecords(Collection<RecordInfo> recordInfo) { //read old file names //register the TransactionSynchronization object TransactionSynchronizationManager.registerSynchronization(new FileDeletionHandler(oldFileLists); //copy new records and their corresponding files } } public class FileDeletionHandler implements TransactionSynchronization { private List<File> filesToBeDeleted; public FileDeletionHandler(List<File> filesToBeDeleted) { this.filesToBeDeleted = filesToBeDeleted; } @Override public void suspend() { } @Override public void resume() { } @Override public void flush() { } @Override public void beforeCommit(boolean readOnly) { } @Override public void beforeCompletion() { } @Override public void afterCommit() { for(File file : filesToBeDeleted) { file.delete(); } } @Override public void afterCompletion(int status) { //status could be either TransactionSynchronization.STATUS_COMMITTED or TransactionSynchronization.STATUS_ROLLED_BACK //or TransactionSynchronization.STATUS_UNKNOWN } }
If you want to execute some code when the transaction rolls back, you could implement that in the afterCompletion() method and have a conditional check on the passed status parameter.
If you have a look at the TransactionSynchronizationManager implementation, you will notice that a List<TransactionSynchronization> objects are maintained in a ThreadLocal variable. This variable is initialized just after the transaction starts (using initSynchronization() method) and cleared when the transaction is suspended or ends.
Posted on October 6, 2011, in spring and tagged spring, transactions. Bookmark the permalink. 2 Comments.
Hi Amit, very well explained!
Hi, really nice work it seeminglessly works. Thank you.