When I need to save a list of objects, and each object should be saved in it's own transaction (so that if one fails they don't all fail), I do it like this:
List<Book> books = createSomeBooks()
books.each { book ->
Book.withNewSession {
Book.withTransaction {TransactionStatus status ->
try {
book.save(failOnError: true)
} catch (ex) {
status.setRollbackOnly()
}
}
}
}
I use Book.withNewSession
because if one book fails to save and the transaction is rolled back, the session will be invalid which will prevent subsequent books from saving. However, there are a couple of problems with this approach:
Is there a better way? One possibility that occurred to me is to dependency-inject the Hibernate SessionFactory
and do this instead
List<Book> books = createSomeBooks()
books.each { book ->
try {
Book.withTransaction {
book.save(failOnError: true)
}
} catch (ex) {
// use the sessionFactory to create a new session, but how....?
}
}
This should do it:
List<Book> books = createSomeBooks()
books.each { book ->
Book.withNewTransaction {TransactionStatus status ->
try {
book.save(failOnError: true)
} catch (ex) {
status.setRollbackOnly()
}
}
}
The session isn't invalid if you rollback, it is just cleared. So any attempts to access entities read from the DB would fail, but writes of not-yet-persisted entities will be just fine. But, you do need to use separate transactions to keep one failure from rolling back everything, hence the withNewTransaction.