Handling Grails transactions programmatically

grails, grails-orm, hibernate, transactions

Solution

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.

Problem

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: - It's a bit verbose - A new session will always be created for each book, even if the previous book succeeded 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....? } } ```

Original source

Related problems