5 ways to initialize lazy associations and when to use them

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Hi, I’m Thorben Janssen from thoughts-on-java.org. Lazy loading of associated entities is a well-established best practice in JPA. Its main goal is to retrieve only the requested entities from the database and to load the related entities only if needed. That is a great approach if you only need the entities you selected in your query. But it creates additional work and can be the cause of performance problems if you also need some of the associated entities. In this video, I want to show you 5 different ways to trigger the initialization of lazy associations and their specific advantages and disadvantages. Let’s start with the most obvious and unfortunately also the most inefficient approach. You don’t worry about the initialization and just use the mapped association. You can see an example of this approach here. Each order has multiple items, and I modeled that as a lazy one-to-many association between the Order and the Item entity. The easiest way to initialize this association is to fetch an Order entity and use the getItems() method. This code works perfectly fine, is easy to read and often used. So what is the problem with it? You probably already know it. This code performs an additional query to fetch the associated entities. That doesn’t sound like a real issue but let’s calculate the number of queries in a more real world-ish scenario. Let’s say we have an entity with 5 associations which we need to initialize. So we will get 1 query to fetch the entity, plus 5 queries to load the associated entites. That are 6 queries in total. That still doesn’t seem like a huge issue. But you often have to select more than 1 entity. Let’s say you select 100 entities. Hibernate then has to perform 500 additional queries. That is called the n+1 select issue, and it should be obvious that this is not a good approach. Sooner or later, the number of additionally performed queries will slow your application down. Therefore you should try to avoid this approach and have a look at some other options. A better option to initialize lazy associations is to use a JPQL query with a JOIN FETCH clause. It tells the EntityManager to load the selected entity and the association within the same query. That avoids all the additional queries we had in the previous approach. Here you can see an example of such a JPQL query. You define the JOIN FETCH clause in the same way as a normal JOIN clause. When I run this test case, you will see that Hibernate executed only 1 query. Here it is, Hibernate fetched the Order entity and the associated Items with 1 query. The advantages and disadvantages of this approach are obvious: The main advantage is that Hibernate fetches all entities within one query. From a performance point of view, this is much better than the first approach. And the main disadvantage is that we need to write additional code which executes the query. But it gets even worse if the entity has multiple associations and we need to initialize different relationships for different use cases. In this case we need to write a query for every required combination of associations we want to initialize. That can become quite a mess. So before you start to write lots of queries, you should think about the number of different fetch join combinations you might need. If the number is low, then this is a good approach to limit the number of performed queries. If not, you should have a look at option 4 and 5. But before I explain the other options, I want to quickly show you that you can also define a JOIN FETCH clause with the Criteria API. You can see a simple CriteriaQuery here. It selects all Order entities from the database, and I call the fetch method on the Root interface to create a JOIN FETCH clause so that Hibernate also loads the associated entities. The advantages and disadvantages are the same as for the JPQL query with a fetch join. Hibernate loads the entity and the associated entities with one query, and you need specific code for every combination of associations. But you often already have lots of use case specific query code, if you are using the Criteria API. So this might not be a huge issue. If you use the Criteria API to build the query, this is a good approach to fetch the associated entities efficiently. You can see the generated SQL query here. It’s the same as in the previous example, and it gets the Order entity together with the associated Item entities. Named entity graphs were introduced in JPA 2.1. You can use them to define a graph of entities that Hibernate shall load from the database. The definition of an entity graph is done via annotations and is independent of the query. I will just show you a quick example of how you can define such a graph. I wrote a blog post that explains NamedEntityGraphs in more details. You should have at it if you’re not familiar with this feature. I provide a link to it in the video description. Here you can see the definition of a @NamedEntityGraph which tells Hibernate to initialize the entity attribute with the name “items”. That is the one that models the lazy one-to-many association between the Order and the Item entity. So, this @NamedEntityGraph does the same as I did with the JOIN FETCH statements in the JPQL and CriteriaQuery. But this one is independent of the query, and you can also use it with the EntityManager.find method. I do that here. I first call the getEntityGraph method with the name of the @NamedEntityGraph to instantiate an EntityGraph. Then I create a Map with query hints and add my graph as a "javax.persistence.fetchgraph“. And in the final step, I provide the Map with query hints as a parameter to the EntityManager.find method. That’s it. Let’s run this test and see if it works. As you can see here, the @NamedEntityGraph worked as expected. Hibernate performed only 1 query to fetch the Order entity with its associated Item entities. This is basically an improved version of the first approach. The only disadvantage is that you need to annotate a named entity graph for each combination of associations that Hibernate shall retrieve within one query. You will need less additional annotations as in our second approach, but it still can become quite messy. Therefore named entity graphs are only a great solution, if you don’t need too many of them and if you reuse them for different use cases. Otherwise, the code will become hard to maintain. The dynamic entity graph is similar to the named entity graph, and I also explained it in more details in one of the older blog posts. The only difference is that you use a Java API to define the entity graph. That provides you more flexibility if you need to adapt your graph based on user input. These 2 lines define the same graph as the annotations in the previous example. It tells Hibernate to initialize the items attribute of the Order entity. And you should be familiar with the rest of this test case. It’s the same as in the previous example. I create a Map of query hints, add the graph and provide the map to the EntityManager.find method. Hibernate handled the EntityGraph in the same way as in the previous example and fetched the Order entity together with the associated Item entities. So, when should you use a dynamic instead of a named entity graph? The definition via an API can be an advantage and a disadvantage. If you need lots of use case specific entity graphs, it might be better to define the entity graph within your Java code. That provides more flexibility and avoids entities with dozens of annotations. On the other hand, the dynamic entity graph requires more code and an additional method to be reusable. I recommend using dynamic entity graphs if you need to define a use case specific graph, which you will not reuse. If you want to reuse the entity graph, it is easier to annotate a named entity graph. OK, that’s it for today. I prepared a cheat sheet with the most important facts of this video. You can find it in the Thoughts on Java Library. If you’re not already a member, you can signup for free. That also gives you free access to other cheat sheets, ebooks, and a video course. You can find a link to it in the video description. But before you go there, please give this video a thumbs up and subscribe below so that you don’t miss any future videos. Bye!
Info
Channel: Thorben Janssen
Views: 14,221
Rating: undefined out of 5
Keywords: lazy loading, hibernate, jpa, tutorial, java, lazy loading in entity framework
Id: Dr5Qn6NC-3Y
Channel Id: undefined
Length: 11min 16sec (676 seconds)
Published: Wed Feb 08 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.