Articles on Java, JavaScript and Web technologies

Hibernate Fetch Strategies Explained

In this post, I will use a different way to explain the fetch strategies that are employed by Hibernate. While there is literature around, it does not highlight strongly that the fetch strategies are also affected by what you fetching.

The Code

I have two entity classes that I will use in this example. A Customer class has a “set” of Account objects. Following is the code and their Hibernate mapping files. The classes are kept simple and minimalistic, so that we focus on their fetching from Hibernate.

I used the hbm2ddl tool to generate the schema and also wrote simple code to poulate the data. I am not showing the code to populate the data. There are two Customer records and each customer has two accounts. This is how the database looked like

Customer Table

Account Table

I wrote a DAO class which has two methods for my testing. I was using Spring and Hibernate together and using the @Transactional annotation to mark the transactions, but you may use code to mark the transactions. One method fetches all the Customer records and the other fetches a specific Customer record by ID. These two methods are important to highlight the behaviours of the fetch strategies.

The first query fetches the customers or the specific customer. When the Customer’s Account is accessed, at that time a subsequent query is fired to fetch that specific customers Account.In case of the list, “N+1” queries will be fired – 1 query which returns N customers and one each for the Accounts of these N Csutomers. If I were to comment out the code that accesses the Accounts and prints them, the second query (or the N subsequent queries in case of list fetch) are not fired.

2)lazy="false"

I changed the mapping of the Account Set as follows and ran the above two code snippets again.

Now this is an interesting case. In case of fetching the list, as soon as the first Customer’s Account is accessed, the second query is fired. It populates the Accounts for ALL the Customers. This is in anticipation that you may be accessing the Accounts of other Customers that were fetched as a list.
However, when a single Customer is fetched, the query fired is same as in case of lazy fetching. It is fired only when the Account is accessed.
In case of a list fetch, this strategy avoids the N+1 selects. For all the N Customers that were fetched, a single fetch populates the Accounts for all of them using a subselect query.

This is also interesting. Notice that for the list fetch, there is no difference between this and the fetch with lazy=”true”. The difference is in the case of single Customer fetch. Here, only a single query is fired. It uses a join between the Customer and the Account table and fetches the entire data in one go. Even if the Accounts for a Customer is not accessed, the query still fetches that data. In other words, lazy fetching is turned off!

5)batch-size="2"

This is the last strategy of batch fetching. This is applied as follows:

Note that there is no impact when a single Customer is fetched. It is same as lazy=”true”. Only when the Account is accessed is the second query fired. However, see that the query to fetch Account in case of list fetch is different. It is fired only when Account of one Customer is accessed. It tries to get the Accounts of “2” Customers in a batch. In other words it also anticipates that a subsequent Customer’s Accounts will be accessed. This is similar to the fetch=”subselect” option, the difference being that with subselect all the Accounts are fetched whereas here, it will be done in batches under the hood.

Conclusion

lazy=”false” is a bad option, you really ought to have a strong case before you go this route. By default keep it (lazy loading) on.

fetch=”subselect” and batch-size=”n” affects the the case of lists being fetched. They do not impact when you are fetching a single Entity object.

fetch=”join” affects the fetching of a single Entitly. It gives the affect of turning off lazy loading by using a join. It does not affect the fetching of lists.

You can have the best of all worlds by using the Criteria APIs. Keep default-lazy=”true” and then depending on the use case, you may specify different Fetchmode. See the Hibernate API documentation of the Criteria API.

I like the helpful information you provide in your articles. Ill bookmark your weblog and check again here regularly. I’m quite certain I will learn plenty of new stuff right here! Good luck for the next! kkbbedadcbdk