Grails event for database-level insert?

316 views
Skip to first unread message

Sitati Kituyi

unread,
Jun 24, 2014, 8:15:27 AM6/24/14
to grails-de...@googlegroups.com
Hi all,

I'm using the @Listener annotation in Grails 2.0.3 to listen for afterInsert events on a specific domain. The events are firing, but I've found that they fire at the point of the save() in a transactional service method, not at the point of insertion into the database after completion of the service method. They also fire when the save is called in the event where the transaction is rolled back due to an exception.

Is there an alternative way to detect actual insertion of a domain into the database?

The context of this is that we're using grails-routing with Camel, and I only want to trigger the sending of a message down a camel route when it is persisted in the database. If we trigger the (asynchronous) call to camel from the same method that saves the domain, there is a race condition where the camel processors' attempts to access the saved domain can happen before the save is flushed to the database. The camel processors are not bound to the same hibernate session as the triggering service, so only see the domain instance if it is actually in the db.

Thanks

jdaug...@jdresources.net

unread,
Jun 24, 2014, 10:36:34 PM6/24/14
to grails-de...@googlegroups.com
We had a similar need in our project and found org.springframework.transaction.support.TransactionSynchronizationManager to assist us.  Since the entity could get rolled back if the transaction rolls back, we added the following method to execute code after a transaction commits:

void executeAfterCommit(Closure c) {
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
            @Override
            void afterCommit() {
                c.call()
            }
        })
    }

We then call this method by passing it a closure with the code we want to call and when the current transaction is finished, the closure is invoked.  This seems to work for us, but be careful, there are a few caveats:
  1. If you throw out of this method, it can cause odd behavior.  To work around this, we have another version of the method that forks an async thread to execute the closure to ensure it doesn't affect the transaction that's committing. 
  2. You can't call this method from the closure since the transaction will have already committed (it won't trigger again)
I don't think we've tried calling it from the events so I'm unsure of the behavior in your case, but I think it would work.  We typically call this where we call save() instead.  Maybe it will help ...

-James

Sitati Kituyi

unread,
Jun 25, 2014, 3:28:30 AM6/25/14
to grails-de...@googlegroups.com
Thanks James, looks like exactly what we need, we'll give this a try.

Does anyone else think the behaviour of afterInsert isn't as advertised? The GORM docs say the event is "Executed after an object is persisted to the database". My reading of that definition suggests it wouldn't be fired in a rolled-back transaction, or immediately after any non-flushed save.
Reply all
Reply to author
Forward
0 new messages