LazyInitializationException: What it is and the best way to fix it
Aug 15, 2023
LazyInitializationException: What it is and the best way to fix it
The LazyInitializationException is one of the most common exceptions when working with Hibernate. There are a few easy ways to fix it. But unfortunately, you can also find lots of bad advice online. The proclaimed fixes often replace the exception with a hidden problem that will cause trouble in production. Some of them introduce performance issues, and others might create inconsistent results. Hibernate throws the LazyInitializationException when it needs to initialize a lazily fetched association to another entity without an active session context. That’s usually the case if you try to use an uninitialized association in your client application or web layer. In this video, I will explain to you what the LazyInitializationException is, which advice you should ignore, and how to fix the exception instead. But before we proceed, if you are new here and want to learn how to build incredible efficient persistence layers with JPA and Hibernate and all types of other Java persistence related stuff, start now by subscribing and clicking the bell, so you don’t miss anything. Links mentioned: 6 Hibernate Mappings You Should Avoid for High-Performance Applicationshttps://thorben-janssen.com/6-hiberna … Best Practices for Many-to-Many Associations with Hibernate and JPAhttps://thorben-janssen.com/best-prac … JPA Entity Graphs: How to Define and Use a @NamedEntityGraphhttps://thorben-janssen.com/jpa-21-en … Entities or DTOs – When should you use which projection?https://thorben-janssen.com/entities- … Like my channel? Subscribe! ➜ http://bit.ly/2cUsid8 Join the free Member Library:https://goo.gl/dtyIIC Read the accompanying post: https://thorben-janssen.com/lazyiniti … Want to connect with me? Blog: https://thorben-janssen.com/ Twitter: https://twitter.com/thjanssen123 Facebook: https://www.facebook.com/thoughtsonjava #LazyInitializationException #JPA #Hibernate
Content
1.2 -> The LazyInitializationException is one of the most
3.9 -> common exceptions when working with Hibernate.
6.4 -> There are a few easy ways to fix it.
8.4 -> But unfortunately, you can also find lots
of bad advice online.
12.52 -> The proclaimed fixes often replace the exception
15.42 -> with a hidden problem that will cause trouble in production.
18.44 -> Some of them introduce performance issues, and others might create inconsistent results.
23.26 -> Hi, I’m Thorben Janssen and in this video,
25.78 -> I will explain to you what the LazyInitializationException is,
29.08 -> which advice you should ignore, and how to fix the exception instead.
32.98 -> But before we proceed, if you are new here
and want to learn how to build incredible
37.12 -> efficient persistence layers with JPA and
Hibernate
40 -> and all types of other Java persistence related staff
43.26 -> start now by subscribing and
clicking the bell, so you don't miss anything.
48.04 -> Hibernate throws the LazyInitializationException
50.88 -> when it needs to initialize a lazily fetched association to another entity
55.66 -> without an active session context.
57.88 -> That’s usually the case if you try to use
an uninitialized association
62.06 -> in your client application or web layer.
67.28 -> Here you can see a test case with a simplified example.
71.02 -> The database query returns an Author entity
with a lazily fetched association to the books
76.28 -> this author has written.
78.02 -> Hibernate initializes the books attributes
with its own List implementation,
82.5 -> which handles the lazy loading.
84.66 -> When you try to access an element in that List or
87.88 -> call a method that operates on its elements,
90.7 -> Hibernate’s List implementation
recognizes that no active session is available
95 -> and throws a LazyInitializationException.
100.48 -> As I said at the beginning, you can find lots of bad advice
104.16 -> on how to fix the LazyInitializationException.
107.44 -> Let me quickly explain which suggestions you
should ignore.
110.94 -> Some developers suggest changing the FetchType of the association to EAGER.
115.98 -> This, of course, fixes the LazyInitializationException,
119.56 -> but it introduces performance problems that will show up in production.
123.76 -> When you set the FetchType to EAGER, Hibernate
will always fetch the association,
127.98 -> even if you don’t use it in your use case.
131 -> That obviously causes an overhead that slows
down your application.
135.22 -> But it gets even worse if you don’t use
the EntityManager.find method
139.46 -> and don’t reference the association in a JOIN FETCH
clause.
143.42 -> Hibernate then executes an additional query
to fetch the association.
147.72 -> This often results in the n+1 select issue,
150.52 -> which is the most common cause of performance issues.
154.3 -> So please, don’t use FetchType.EAGER.
156.92 -> As explained in various articles on my blog and in videos on this channel,
160.94 -> you should always prefer FetchType.LAZY.
164.42 -> When using the Open Session in View anti-patter, you open
167.9 -> and close the EntityManager or Hibernate Session in your view layer.
172.3 -> You then call the service layer, which opens
and commits a database transaction
177.16 -> Because the Session is still open after the
service layer returned the entity,
181.48 -> the view layer can then initialize the lazily fetched
association.
185.78 -> But after the service layer committed the
database transaction, there is no active transaction.
191.54 -> Because of that, Hibernate executes each SQL statement
194.86 -> triggered by the view layer in auto-commit mode.
197.96 -> This increases the load on the database server
because it has to handle an extra transaction
202.94 -> for each SQL statement.
204.98 -> At the end of each of these transactions,
the database has to write the transaction log to the disc,
210.26 -> which is an expensive operation.
212.9 -> The increased pressure on your database isn’t the only downside of this anti-pattern.
217.36 -> It can also produce inconsistent results because you are now using
221.54 -> 2 or more independent transactions.
224.52 -> As a result, the lazily fetched association
might return different data than your service
229.42 -> layer used to perform the business logic.
231.86 -> Your view layer then presents both information together
235.02 -> and it might seem like your application manages inconsistent data.
239.5 -> Unfortunately, Spring Boot uses the Open Session
in View anti-pattern by default.
244.36 -> It only logs a warning message.
246.34 -> You can deactivate it by setting the spring.jpa.open-in-view parameter
251.22 -> in your application.properties file to false.
254.76 -> OK, so what should you do instead?
257.46 -> The right way to fix a LazyInitializationException
is to fetch all required associations
262.7 -> within your service layer.
264.58 -> The best option for that is to load the entity with all required associations in one query.
270.44 -> Or you can use a DTO projection, which doesn’t support lazy loading
274.36 -> and needs to be fully initialized before you return it to the client.
279.38 -> Let’s take a closer look at the different
options to initialize lazily fetched association
284.64 -> and at the best way to use DTO projections.
288.02 -> The easiest way to load an entity with all
required associations
291.92 -> is to perform a JPQL or Criteria Query
295.12 -> with one or more LEFT JOIN FETCH clauses.
297.74 -> That tells Hibernate to not only fetch the entity referenced in the projection
302.3 -> but also to fetch all associated entities referenced in the LEFT JOIN FETCH clause.
310.2 -> Here you can see a simple example of such a query.
313.48 -> The query selects Author entities,
315.82 -> and the LEFT JOIN FETCH clause tells Hibernate to also fetch the associated Book entities.
321.42 -> As you can see in the generated SQL statement,
323.88 -> Hibernate not only joins the 2 corresponding tables in the FROM clause,
327.88 -> it also added all columns mapped by the Book entity to the SELECT clause.
332.84 -> As you can see in the log messages,
334.54 -> the query returned an Author entity with an initialized books association.
342.04 -> You can do the same using a @NamedEntityGraph.
345.08 -> The main difference is that the definition of the graph is independent of the query.
349.7 -> That enables you to use the same query with different graphs
353.32 -> or to use the same graph with various queries.
358.76 -> I explained @NamedEntityGraphs in great detail
in a previous video.
362.88 -> So, I keep the explanation short.
364.98 -> You can define the graph by annotating one of your entity classes
368.76 -> with a @NamedEntityGraph annotation.
371.3 -> Within this annotation, you can provide multiple
@NamedAttributeNode annotations
375.64 -> to specify the attributes that Hibernate shall fetch.
379.36 -> To use this graph, you first need to get a reference to it from your EntityManager.
384.34 -> In the next step, you can set it as a hint on your query.
388.26 -> If you look at the generated SQL statement,
you can see that there is no difference between a
393.3 -> LEFT JOIN FETCH clause and a @NamedEntityGraph.
396.72 -> Both approaches result in a query that selects
all columns mapped by the Author
400.98 -> and the Book entity
402.44 -> and return Author entities with an initialized books association.
409.08 -> The EntityGraph API provides you the same functionality as the @NamedEntityGraph annotation.
414.86 -> The only difference is that you use a Java
API instead of annotations to define the graph.
420.14 -> That enables you to adjust the graph definition dynamically.
426.78 -> As you can see in the code, the API-based definition of the graph follows the same concepts
431.54 -> as the annotation-based definition.
434.04 -> You first create the graph by calling the
createEntityGraph method.
437.98 -> In the next step, you can add multiple attributes
nodes and subgraphs to the graph.
443.04 -> I explain all of that in great detail in JPA Entity Graphs:
446.76 -> How to Dynamically Define and Use an EntityGraph.
450.5 -> After you defined the graph, you can use it
in the same way as a @NamedEntityGraph,
455.5 -> and Hibernate generates an identical query for
both of them.
461.92 -> Fetching all required associations when you
load the entity fixes the LazyInitializationException.
467.9 -> But there is an alternative that’s an even better fit for all read operations.
472.46 -> As I showed in a previous article, DTO projections
provide significantly better performance
477.87 -> if you don’t want to change the retrieved information.
483.36 -> In these situations, you can use a constructor expression
486.48 -> to tell Hibernate to instantiate a DTO object
489.44 -> for each record in the result set.
491.58 -> Hibernate then generates an SQL statement that only selects the columns that are mapped
496 -> by the attributes that you reference in the constructor call.
499.44 -> This often reduces the number of selected columns
502.06 -> and improves the performance even further.
507.5 -> If you have used Hibernate for a while, you probably had to fix at least one LazyInitializationException.
513.38 -> It’s one of the most common ones when working
with Hibernate.
516.76 -> As I explained in this video, you can find
lots of advice online on how to fix this exception.
522.46 -> But a lot of these suggestions
524.08 -> only replace the exception with problems that will show up in production.
528.32 -> There are only 2 good solutions to this problem:
531.74 -> You initialize all required associations when
you load the entity using a LEFT JOIN FETCH clause
537.4 -> or a @NamedEntityGraph or the EntityGraph API.
540.94 -> Or You use a DTO projection instead of entities.
544 -> DTOs don’t support lazy loading, and you
need to fetch all required information
548.34 -> within your service layer.
552.9 -> OK, that’s it for today.
555 -> If you want to learn more about Hibernate, you should join the free Thoughts on Java Library.
559.36 -> It gives you free access to a lot of member-only content
562.36 -> like a cheat for this video and an ebook about using native queries with JPA and Hibernate.
567.78 -> I’ll add the link to it to the video description below.
570.84 -> And if you like today’s video, please give it a thumbs up and subscribe below.
574.94 -> Bye
Source: https://www.youtube.com/watch?v=6p-fuwVxryg