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 = Status.READ ; book.save() }
println (Book.findAllByStatus (Status.READ)) //will print an empty list
println (Book.list().findAll (it.status == Status.READ)) // will print all books
I cannot understand why the last two queries could return different results.
However if I make the following modification of book.save(flush:true). Both of the println statements will return all books.
I was under the impression that this was not necessary within a single application.
For reference I'm using
@Hoàng Long
My problem is demonstrated below, suppose action1/action2 are both called many many times, in no particular pattern
def action1 = {
Foo foo = Foo.get(params.id)
//... modify foo
foo.save() //if I flush here, it will be inefficient if action1 is called in sequence
}
def action2 = {
//if I flush here, it will be inefficient if action2 is called in sequence
List<Foo> foos = Foo.findAllByBar (params.bar)
//... do something with foos
}
One solution would be to have a flag which is is set by action1 and used by action2 to flush if necessary. My issue is that this is an overly complex solution, which is not scalable as the complexity of DB calls increases.
boolean isFlushed = true
def action1 = {
Foo foo = Foo.get(params.id)
//... modify foo
foo.save()
isFlushed = false
}
def action2 = {
if (!isFlushed) {
//flush hibernate session here
}
List<Foo> foos = Foo.findAllByBar (params.bar)
//... do something with foos
}
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.
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()
}
}