zoran119
zoran119

Reputation: 11307

Any documentation for `saveAll`?

I have come across some Grails code as follows:

Book.saveAll(bookList)

where bookList is a List of Book domain instances. While this appears to be working fine (saving all the Book instances) while run-app, functional tests fail with the following error:

Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.

Then I wanted to see some documentation about saveAll and I cannot seem to be able to find any. Is there any documentation? Should this method even be used?

Upvotes: 4

Views: 5446

Answers (2)

Etibar - a tea bar
Etibar - a tea bar

Reputation: 1962

Basically, saveAll doesn't flush. After using saveAll if you want your changes in the database immediately, you can get current session and flush it. It's how Hibernate works: When you call flush, it will flush the Hibernate session, persistent all data in session to the 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. There are different way of flushing, you can save all the datas and flush in the end.

def hibSession = sessionFactory.getCurrentSession()

hibSession.flush()

We faced the same problem. Tested which method is faster. The test were done with 300 items.

  • With each Book save.(flush: true, failOnError: true) took 328 517 milliseconds;

list.each{ Book.save(flush: true, failOnError: true) }

  • With each order save() , after everything finished one time flush in the end 106 485 milliseconds; 3 times faster, still slow

list.each{Book.save()};
def hibSession = sessionFactory.getCurrentSession();
hibSession.flush()

  • In the end saveAll() and flush() 19 944 milliseconds. 15 times faster.

Book.saveAll(list);
def hibSession = sessionFactory.getCurrentSession();
hibSession.flush()

Upvotes: 7

Burt Beckwith
Burt Beckwith

Reputation: 75671

I'm not sure why that's not documented, but there are quite a few gaps in the docs :) The implementation is pretty basic though, it just loops through the list and calls save on each. So you could convert it to your own loop and it should work in both scenarios, e.g.

for (book in bookList) {
   book.save()
}

This has the advantage that you can check the errors of each in the loop, and it's more obvious that multiple things are being saved and that this should be done in a transaction.

Upvotes: 1

Related Questions