11.3 Asynchronous GORM 3.1.1

See the light - agile, industrial strength, rapid web application development made easy

(Quick Reference) # 11.3 Asynchronous GORM - Reference Documentation Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith, Lari Hotari Version: 3.1.1 ## 11.3 Asynchronous GORM Since Grails 2.3, GORM features an asynchronous programming model that works across all supported datastores (Hibernate, MongoDB etc.). Although GORM executes persistence operations asynchronously, these operations still block as the underlying database drivers are not asynchronous. Asynchornous GORM is designed to allow you to isolate these blocking operations onto a separate thread you can scale and control allowing your controller layer to remain non-blocking. ### Async Namespace The Asynchronous GORM API is available on every domain class via the `async` namespace. For example, the following code listing reads 3 objects from the database asynchronously:

    import static grails.async.Promises.*def p1 = Person.async.get(1L)
    def p2 = Person.async.get(2L)
    def p3 = Person.async.get(3L)
    def results = waitAll(p1, p2, p3)
Using the `async` namespace, all the regular GORM methods are available (even dynamic finders), but instead of executing synchronously, the query is run in the background and a `Promise` instance is returned. The following code listing shows a few common examples of GORM queries executed asynchronously:

    import static grails.async.Promises.*Person.async.list().onComplete { List results ->
      println "Got people = ${results}"
    }
    def p = Person.async.getAll(1L, 2L, 3L)
    List results = p.get()def p1 = Person.async.findByFirstName("Homer")
    def p2 = Person.async.findByFirstName("Bart")
    def p3 = Person.async.findByFirstName("Barney")
    results = waitAll(p1, p2, p3)
### Async and the Session When using GORM async each promise is executed in a different thread. Since the Hibernate session is not concurrency safe, a new session is bound per thread. This is an important consideration when using GORM async (particularly with Hibernate as the persistence engine). The objects returned from asynchronous queries will be detached entities. This means you cannot save objects returned from asynchronous queries without first merging them back into session. For example the following will not work:
    def promise = Person.async.findByFirstName("Homer")
    def person = promise.get()
    person.firstName = "Bart"
    person.save()
Instead you need to merge the object with the session bound to the calling thread. The above code needs to be written as:
    def promise = Person.async.findByFirstName("Homer")
    def person = promise.get()
    person.merge()
    person.firstName = "Bart"
Note that `merge()` is called first because it may refresh the object from the cache or database, which would result in the change being lost. In general it is not recommended to read and write objects in different threads and you should avoid this technique unless absolutely necessary. Finally, another issue with detached objects is that association lazy loading will not work and you will encounter `LazyInitializationException` errors if you do so. If you plan to access the associated objects of those returned from asynchronous queries you should use eager queries (which is recommended anyway to avoid N+1 problems). ### Multiple Asynchronous GORM calls As discussed in the previous section you should avoid reading and writing objects in different threads as merging tends to be inefficient. However, if you wish to do more complex GORM work asynchronously then the GORM async namespace provides a `task` method that makes this possible. For example:

    def promise = Person.async.task {
        withTransaction {
           def person = findByFirstName("Homer")
           person.firstName = "Bart"
           person.save(flush:true)
        }
    }Person updatedPerson = promise.get()
Note that the GORM `task` method differs from the static `Promises.task` method in that it deals with binding a new session to the asynchronous thread for you. If you do not use the GORM version and do asynchronous work with GORM then you need to do this manually. Example:

    import static grails.async.Promises.*def promise = task {
        Person.withNewSession {
        	// your logic here
        }
    }
### Async DetachedCriteria The `DetachedCriteria` class also supports the `async` namespace. For example you can do the following:

    DetachedCriteria query = Person.where {
        lastName == "Simpson"
    }def promise = query.async.list()
| Quick Reference (hide)