Grails Issue 'Not Processed by Flush()' Root Causes

| Comments

I’ve learned some painful lessons recently around hibernate sessions in grails that are pretty obvious in retrospect. I wanted to get some quick notes down as there’s not a lot of good information out there around this in grails that I could find. Here are some quick bullet points about what I’ve learned around grails management of the hibernate session and when it gets flushed.

  • Grails normally manages when the session gets flushed, sometimes this happens when you might not be expecting it and isn’t always caused by a save/delete. It can be caused by doing a read only command too.
  • If you have an object that you’ve made changes to (it’s dirty), if you make any calls to the database involving that object (such as a findBy using the object), grails will automatically flush the session so that the query that you make is consistent.
  • if it didn’t do this, your query wouldn’t have the dirty information available to it and your query would return results inconsistent with reality in the session you’re using. So if you have a parent object that’s dirty because you added a child object, but before saving it, you called Children.findAllByParent(parent). The parent object gets flushed to the database so the findAll is correct.
  • If that’s not a big deal to you (you’re querying something that doesn’t have anything to do with the dirty fields), you can use Foo.withNewSession { } closure to make the database call without flushing the current session
  • if it is a big deal to you, then let the session flush and let the object get persisted.
  • but if in the process of flushing (before the findBy/query gets run) additional objects are brought into the session, you’ll hit the dreaded ‘collection [com.foo.bar.Baz.quxs] was not processed by flush()’
  • One place where this could happen is if you have a custom validator that does a query to the database and pulls any related objects back that aren’t already in the session (ex: a validator on Parent that asserts that all children are younger than the parent).
  • You can use Foo.withNewSession in your custom validators to try to get around this. But beware a StackOverflow error (or a red zone memory exception on OSX because of a JVM bug) where it gets into a loop of flushing out sessions
  • If you do use Foo.withNewSession, make sure you understand that the database calls that you make will be completely unaware of any changes to the current object. Also that you won’t be able to use the instance of the object passed to the custom validator, but will instead have to do Foo.load(object.id) and then use the result of that to query the DB. The performance of all of this probably sucks (but that might not matter for your use case).
  • Chances are that what you should really be doing though is using a service/transaction and actually saving the object first before calling the dynamic finder on the dirty object. Then, when it’s persisted, you can safely use the clean object in your finder.

Comments