Unveil magic of hibernate lazy loading

Print Friendly, PDF & Email

[dropcap]R[/dropcap]ecently we have discussed about the performance of retrieving collections/relations/associations inside objects. By the way, we also review the machinery that hibernate handles these relational concepts to improve the effectiveness of database operations. One of the techniques being implemented in Hibernate is lazy loading. In this post, I want to share you what I have learned how hibernate lazy loading works with a toy application.

Design the application

Here are our domain classes

package com.itersdesktop.javatechs.grails.hibernate

class Book implements Serializable {
    String title
    static belongsTo = [author: Author]
    static constraints = {
    }
}
package com.itersdesktop.javatechs.grails.hibernate

class Author implements Serializable {
    String name
    static hasMany = [books: Book]
    static constraints = {
    }
}

To test the application simply, we will try to create some toy records in bootstrap.groovy  as below:

import com.itersdesktop.javatechs.grails.hibernate.Author
import com.itersdesktop.javatechs.grails.hibernate.Book

class BootStrap {

    def init = { servletContext ->
        def ethan = new Author(name: 'Ethan').save()
        def book1 = new Book(title: 'The Fairytale Hairdresser and Aladdin')
        def book2 = new Book(title: 'The How to be British Collection')
        ethan.addToBooks(book1)
        ethan.addToBooks(book2)
    }
    def destroy = {
    }
}

In order to look at exactly when hibernate will invoke SQL queries, we can either turn on SQL logging in DataSource.groovy  or enable the general query log. I suggest that we should use the former for simplicity.

...
development {
        dataSource {
            dbCreate = "create-drop" // one of 'create', 'create-drop', 'update', 'validate', ''
            url = "jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE"
            loggingSql = true
        }
    }
...

Now let’s create a controller to hold our test code (just for convenience, this could also be done in a groovy console):

package com.itersdesktop.javatechs.grails.hibernate

class TestController {
    def index() {
        println "-- Starting controller"
        def ethan = Author.findByName('Ethan')
        println "author name is $ethan.name"
        def myBooks = ethan.books
        println "books are now stored in a variable"
        myBooks.each({
             println it.title
        })
        println myBooks.class.name
        render "Finish!"
    }
}

The method just retrieves the author named ‘Ethan’ that has been created in BootStrap, then collect all his books and print out their name.

Have you ever wondered that how many query commands could hibernate issue from just the simple method index  of TestController? It might be called at the line 6, 8 or 10. Now we are going to go through the code and analyse phenomenon could be occurred.

Forecast likely circumstances

At the line 6, we are using a dynamic finder to look up author based its name. Hibernate is likely to issue a query to get the instance of Author class at which name is ‘Ethan’.

[box type=”note” ]Dynamic method that uses the properties of the domain class to create query method expressions that return all matching instances of the domain class.

See more at: http://docs.grails.org/2.5.5/ref/Domain%20Classes/findAll.html[/box]

At the line 8, we are asking for the books  field where hibernate will retrieve them. Unfortunately Grails uses lazy loading by default, so we cannot see any queries to be issued from this call. Indeed, books haven’t been touched at this point. To ensure the performance, hibernate lets them lived as soon as there are another actually operations hitting the database.

Hibernate won’t actually hit the database to retrieve the data until the line 10 because we expect to get individual book via iterating on the books collection of the given author.

The line 13 reveals how the magic happens. We expect myBooks  to be an instance of List , but it is literally one of PersistentSet.

Analyse SQL queries log

--- Starting controller
Hibernate: select this_.id as id1_0_0_, this_.version as version2_0_0_, this_.name as name3_0_0_ from author 
this_ where this_.name=? limit ?
author name is Ethan
books are now stored in a variable
Hibernate: select books0_.author_id as author_i3_0_0_, books0_.id as id1_1_0_, books0_.id as id1_1_1_, 
books0_.version as version2_1_1_, books0_.author_id as author_i3_1_1_, books0_.title as title4_1_1_ 
from book books0_ where books0_.author_id=?
The Fairytale Hairdresser and Aladdin
The How to be British Collection
org.hibernate.collection.internal.PersistentSet

The output above proofs what I have explained you in the previous sentences.

This writing was given birth to based on what I had read from [1] and various experiences on real projects I am working on. Hopefully you find more interesting as well as helpful from this post. It’s more respectful to have your comments and suggestions in the comment sections.

Source codes

The toy application can be found at https://bitbucket.org/it4bus/hibernate-lazy-evaluation.

References

[1] Hibernate magic with lazy evaluation, accessed 25th February, 2017

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.