Motivation:
From performance perspective, we must avoid loading from the database more data than needed. Attribute lazy loading allows us to load only the needed attributes. This is especially useful for avoiding loading uncessary heavy attirbutes (CLOB, BLOB, VARBINARY, and so on).
Description:
By default, the attributes of an entity are loaded eagerly (all at once).
But, we can load them lazily as well. This is useful for column types that store large amounts of data: CLOB, BLOB, VARBINARY, etc or details that should be loaded on demand. In this application, we have an entity named Author. Its properties are, id, name, genre, avatar, and age. And, we want to load the id, name and genre eagerly, while avatar should be loaded lazily. But, returning entities (converted as JSON) that contain un-fetched lazy attributes from a REST controller (@RestController) will cause lazy initialization exceptions because Jackson tries to force the fetching of these attributes outside a Hibernate session.
But, let's see how we can overcome these lazy initialization exceptions.
Key points:
For Maven, in pom.xml, activate Hibernate Bytecode Enhancement (e.g. use Maven Bytecode Enhancement plugin):
In the entity, annotate the attributes that should be loaded lazy with @Basic(fetch = FetchType.LAZY)
Annotate the Author entity with @JsonFilter("AuthorId") :
Create and configure the AuthorId filter to be used by default via SimpleBeanPropertyFilter.serializeAll() :
At controller level (in the needed endpoint) override the AuthorId filter with one as SimpleBeanPropertyFilter.filterOutAllExcept("id", "name", "age", "genre") and return MappingJacksonValue
A controller endpoint that need to use the overriding version of AuthorId filter should rely on MappingJacksonValue:
In application.properties, disable Open Session in View:
Run the following requests (via BookstoreController):
Lazily fetch the avatar of an author by id: localhost:8080/author/avatar/{id}
Fetch authors by age greater than or equal to the given age without avatar: localhost:8080/authors/{age}
Fetch authors by age greater than or equal to the given age with and avatar (but, don't do this in production - notice the N+1 issue caused by looping the list of authors and triggering SQLs for fetching the avatar of each author): localhost:8080/authors/details/{age}
Most probably you'll need to read the following two articles as well:
Tam Ta Da Dam! :) The complete code is available on GitHub.
If you need a deep dive into the performance recipes exposed in this repository then I am sure that you will love my book "Spring Boot Persistence Best Practices".
Commentaires