Hibernate relations : Data fetch tips explained
Motivation
Using ORM like Hibernate may ease your communication with DB , but it may impacts application performance badly in case you not aware what happens behind the scene , we will discuss here some tips regarding to deal with relations in Hibernate.
Lazy and Eager relation loading
Eager loading of relations means that whenever I ask for entity it will load all relations associated with it even if you will not use them , this may cause performance issue and became worst in case of multiple relations.
Lazy loading of relations means that Hibernate will not fetch any relation till you request them by any getter methods , this will save your performance when fetch data for first time , but be careful , if you already need the relation also , that may harms you because when you fire getter methods Hibernate will fire start another trip to DB to fetch the data and instead of get data in one request you did two.
So, You have to know what are needs of your logic and customize the fetch strategy based on that.
Static fetch strategy to dynamic one , use entity graph
By using Hibernate relation annotation like @OneToMany , @ManyToOne and attach fetch strategy to it you are providing static strategy to relation , but what if you need in some cases LAZY and sometimes need it EAGER , for this case you can use Entity Graph
EntityGraph is a mechanism helps you to provide a shape of entity that you want Hibernate to fetch and override default fetch strategy in that case.
With Post entity we added @NamedEntityGraph to define a graph of entity we want to fetch as top image we need a graph that fetch the Post with associated Comments in one trip even we added LAZY loading for comments relation.
Then we can use @EntityGraph annotation to ask Hibernate to grep this shape of entity by name we defined earlier as below.
Another way of fetch strategies, @Fetch
@Fetch used to tell hibernate the shape of SQL statement that will perform to get data and has three values : SELECT , SUBSELECT and JOIN
SELECT
this is the default option and this option will fire SELECT statement for each Post to get associated Comments , and this impact performance regarding to multiple round trips between application and DB.
Recommended by LinkedIn
Note: you can tweak this performance impact by using @BatchSize(size) , this will make Hibernate to group some SELECT statement and fire them in one round trip.
Hibernate:
select
post0_.id as id1_1_,
post0_.content as content2_1_,
post0_.created_at as created_3_1_,
post0_.is_read as is_read4_1_
from
post post0_
Hibernate:
select
comments0_.post_id as post_id4_2_1_,
comments0_.id as id1_2_1_,
comments0_.id as id1_2_0_,
comments0_.content as content2_2_0_,
comments0_.created_at as created_3_2_0_,
comments0_.post_id as post_id4_2_0_
from
post_comment comments0_
where
comments0_.post_id in (
?, ?, ?, ?, ?
)
But in case of a lot of relations and big batch size it make impact your memory.
SUBSELECT
This option will fire one select statement for Comments and will add WHERE clause with IN operation and sub-select the IDs from Post matching the WHERE clause you used to get Posts.
Hibernate:
select
post0_.id as id1_1_,
post0_.content as content2_1_,
post0_.created_at as created_3_1_,
post0_.is_read as is_read4_1_
from
post post0_
Hibernate:
select
comments0_.post_id as post_id4_2_1_,
comments0_.id as id1_2_1_,
comments0_.id as id1_2_0_,
comments0_.content as content2_2_0_,
comments0_.created_at as created_3_2_0_,
comments0_.post_id as post_id4_2_0_
from
post_comment comments0_
where
comments0_.post_id in (
select
post0_.id
from
post post0_
)
JOIN
This option will enable EAGER fetch strategy and get all Comments with the Post in one trip
Resources
GitHub demo