views:

24

answers:

1

Hi,

I'm using Spring application events within my service layer to notify the wider system when specific events occur. The issue I have is that the events are fired within a transactional context (I'm using Spring's @Transactional annotation). The danger is that I fire an event and then the transaction fails on commit (can happen when using, for example, Hibernate). In this scenario, the event listeners will be assuming some state that will then be rolled back after they've executed. The danger here is that I may, for example, have sent an email to confirm a user's registration on a website when, in fact, their user account was not actually created.

Is there a way, preserving the use of annotations, to somewhere flag an event to be fired after the transaction commits? It kind of seems somewhat analogous to using SwingUtilities.invokeLater(Runnable runnable) when doing GUI programming in Java Swing. I want to say, execute this bit of code later on once the current transaction commits successfully.

Any ideas?

Thanks,

Andrew

+1  A: 

The proper way to solve your problem with confirmation emails is probably to use a distributed transactions with a JMS resource participating in them.

However, as a quick-and-dirty solution, you may try to create a wrapper around a PlatformTransactionManager which will execute Runnables registered in some ThreadLocal storage after successfull commit (and remove it from ThreadLocal after rollback). Actually, AbstractPlatformTransactionManager have exactly this kind of logic with TransactionSynchronizations, but it's buried too deep into its implementation details.

axtavt
I've gone with the quick-and-dirty solution for now. I've built a ThreadLocal based mechanism that associates a queue of Runnable objects with a TransactionStatus object. On commit() or rollback() of a TransactionStatus I either execute the Runnable objects or discard them. It works quite nicely.
drewzilla