I have a strange situation which appears to indicate a GORM cacheing problem
//begin with all book.status\'s as UNREAD
Book.list().each { book.status = Statu
In your case, the first statement return empty list because it reads data from the database, but the data isn't there yet.
It's how Hibernate works: When you call save with (flush: true)
, it will flush the Hibernate session, persistent all data in session to database immediately. If not using (flush:true)
, the data is only recorded in Hibernate session and only get persisted in database when Hibernate session is flushed. The time to flush the session is automatically determined by Hibernate to optimize the performance.
Generally, you should let Hibernate do the work for you (for optimization sake) - unless you want the data are persisted right away.
According to Peter Ledbrook:
Let Hibernate do it's job and only manually flush the session when you have to, or at least only at the end of a batch of updates. You should only really use if you're not seeing the data in the database when it should be there. I know that's a bit wishy-washy, but the circumstances when such action is necessary depend on the database implementation and other factors.
From GORM Gotchas - part 1
UPDATE: to be clear about how to flush the session one time after all the object get saved:
import org.hibernate.*
class SomeController {
SessionFactory sessionFactory
def save = {
assert sessionFactory != null
// loop and save your books here
def hibSession = sessionFactory.getCurrentSession()
assert hibSession != null
hibSession.flush()
}
}
Do I ever need to explicitly flush GORM save calls in grails?
In short Yes!, if you want to use the object immediately as you are doing in your code.
I faced same problem, so this is the picture I got after reading some refs.
This is hibernate session issue.
Hibernate session is created when controller action is called and ends when the action returns ( or dies with error early). If a code is not calling any transactional code Hibernate's db interaction can be depicted like this:
Assume the entry action name is actionName and call to the action completes without any error.
NB:The middle bar ( 2nd level cache is disabled) because there is no any transactional code.
if the above same code has error:
But if your action is calling transactional method or is creating inline transaction with withTransaction ( and assume the call to the action completed without any error).
If the above code has an error:
I hope it helps, but if I made any error or missed to include big point , comment me I will update my pics.
For added info, you can't use flush or save(flush:true) in your domain class events (afterUpdate, beforeUpdate, ect) It will cause a stack overflow error. You can use save() without flush though.
gorm docs
I wonder what was your FlushMode setting.
By default it is set to "auto" and it means that session is flushed before every query which hits DB directly (and probably in other cases too). In that case your Foo.findAllByBar should flush the session first (possible performance issue!) and read correct value from the DB.
There are two other values for FlushMode and if you set one of them then it would explain your problems. First is "manual" which means you decide to manual flush session (e.g. with save(flush:true)). If you don't do that then Foo.findAllByBar reads outdated DB state. Second one is "commit" which means that session is flushed with every transaction commit. That is quite handy if you use "withTransaction" statement in grails.
Resources: http://schneide.wordpress.com/2011/03/08/the-grails-performance-switch-flush-modecommit/ http://docs.jboss.org/hibernate/entitymanager/3.5/reference/en/html/objectstate.html#d0e1215