- {{node.title}}
{{node.type}} · {{ node.urlSource.name }} · by {{node.authors[0].realName }}
Best Performance Practices for Hibernate 5 and Spring Boot 2 (Part 2)
Best Performance Practices for Hibernate 5 and Spring Boot 2 (Part 2)
Make sure you are practicing the best performance practices in your Spring Boot and Hibernate projects.
Nov. 19, 18 · Java Zone ·
Comment (0)
Join the DZone community and get the full member experience.
Java-based (JDBC) data connectivity to SaaS, NoSQL, and Big Data. Download Now.
In our previous installment, we took a look at some of the best performance practices in Hibernate 5 and Spring Boot 2. We are going to take a look at remaining tips and tricks you should be using in your projects. Let’s get to it!
"Item: 26: How To Extract DTOs Via SqlResultSetMapping & NamedNativeQuery"
"Item 27: How To Extract DTOs Via javax.persistence.Tuple And Native SQL"
"Item 28: How To Extract DTOs Via javax.persistence.Tuple And JPQL"
"Item 29: How To Extract DTOs Via Constructor Expression And JPQL"
"Item 30 How To Extract DTOs Via ResultTransformer And Native SQL"
"Item 31: How To Extract DTOs Via ResultTransformer And JPQL"
32. DTOs Via Blaze-Persistence Entity Views
Description: Fetching more data than needed is prone to performance penalties. Using DTOs allows us to extract only the needed data. In this application, we rely on Blaze-Persistence entity views.
Key points:
- For Maven, add in
pom.xml
the dependencies specific to Blaze-Persistence - Configure Blaze-Persistence,
CriteriaBuilderFactory
, andEntityViewManager
- Write an entity view via an interface in the Blaze-Persistence fashion
- Write a Spring-centric repository by extending
EntityViewRepository
- Call a method of this repository, such as
findAll()
,findOne()
, etc. - For using Spring Data Projections, check item number 9 above
Source code can be found here.
Item 33: How @ElementCollection Without @OrderColumn Works
Inserts and deletes that affects @ElementCollection
without @OrderColumn
are prone to performance penalties. With@OrderColumn,
the things are getting a little bit better.
Description: This application reveals the possible performance penalties of using @ElementCollection
— in this case, without @OrderColumn
. As you can see in the next issue (item 34), adding@OrderColumn
can mitigate some performance penalties.
Key points:
- An
@ElementCollection
doesn’t have a Primary Key - An
@ElementCollection
is mapped in a separate database table - Avoid
@ElementCollection
when you have a lot of inserts and deletes in/from it since the database has to delete all existing rows in order to add a new one or delete one - The more items we have in this table, the greater the performance penalty
Output sample:
Source code can be found here.
Item 34: How @ElementCollection With @OrderColumn Works
Inserts and deletes that affect@ElementCollection
with@OrderColumn
are prone to performance penalties. But, it is better than using it without @OrderColumn.
Description: This application reveals the possible performance penalties of using @ElementCollection
. In this case, with@OrderColumn
. But, as you can see in this application, by adding@OrderColumn
can mitigate some performance penalties when operations take place near the collection tail (e.g., add/remove at/from the end of the collection). Mainly, all elements situated before the adding/removing entry are left untouched, so the performance penalty can be ignored if we affect rows close to the collection tail.
Key points:
- An
@ElementCollection
doesn’t have a Primary Key - An
@ElementCollection
is mapped in a separate database table - Prefer
@ElementCollection
with@OrderColumn
when you have a lot of inserts and deletes from the collection tail - The more items are inserted/removed from the beginning of this table, the greater the performance penalty
Output sample:
Source code can be found here.
Item 35: How to Avoid Lazy Initialization Caused by Open Session In View Anti-Pattern (1 Session/1 HTTP Request-Response)
Open-Session In View
will fetch the lazy entities (if any) even if you don’t use them further, and this can lead to a serious performance penalty.
Description: TheOpen-Session in View
anti-pattern is activated by default in Spring Boot. If you prefer to use it, then it is a good approach to try to mitigate its performance penalties as much as possible. One optimization consists in marking theConnection
as read-only, which would allow the database server to avoid writing to the transaction log. Another optimization consists in explicitly setting the lazy properties of the fetched entities when you don’t want them to be lazily initialized.
Key points:
- Fetch an entity and set the lazy properties explicitly
- You can do this in the service or controller layer, depending on where it fits better to your case, but outside of an explicit transaction
- Why is this working? Why we can set the property of a managed entity and not trigger the flush? Well, the answer can be found in the documentation of
OpenSessionInViewFilter,
which specifies that:
" NOTE: This filter will by default not flush the Hibernate Session, with the flush mode set to FlushMode.NEVER. It assumes to be used in combination with service layer transactions that care for the flushing: The active transaction manager will temporarily change the flush mode to FlushMode.AUTO during a read-write transaction, with the flush mode, reset to FlushMode.NEVER at the end of each transaction. If you intend to use this filter without transactions, consider changing the default flush mode (through the "flushMode" property)."
Output sample:
Source code can be found here.
Item 36: How to Use Spring Projections (DTOs) and Inner Joins
SQL JOINS and DTOs are our allies in the fight against N+1 issues. Items 36-42 contain a bunch of examples.
Description: This application is a proof of concept for using Spring Projections (DTOs) and inner joins written via JPQL and native SQL (for MySQL).
Key points:
- Define several entities (e.g.,
Tournament
andPlayer
in a bidirectional@OneToMany
relationship) - Populate the database with some test data (e.g., check the file,
resources/data-mysql.sql
) - Write interfaces (projections) that contain getters for the columns that should be fetched from the database (e.g.,
TournamentPlayerNameDto
,PlayerRankNameDto
,TournamentIdNameDto
) - Write inner joins queries using JPQL/native SQL, for example:
– Query the tournaments of all players
(localhost:8080/tournamentsOfPlayersNamesInnerJoinJpql
)
– Query all tournaments that have players with rank smaller or equal to "rank"
(localhost:8080/tournamentsIdNameByRankInnerJoinSql
)
Source code can be found here.
You may also like the following:
"Item 37: How To Use Spring Projections(DTOs) And Left Joins"
"Item 38: How To Use Spring Projections(DTOs) And Right Joins"
"Item 39: How To Use Spring Projections(DTOs) And Full Joins"
"Item 40: How To Use Spring Projections(DTOs) And Left Excluding Joins"
"Item 41: How To Use Spring Projections(DTOs) And Right Excluding Joins"
"Item 42: How To Use Spring Projections(DTOs) And Outer Excluding Joins"
Item 43: How to Use Spring Post Commits
Typically, the performance issue described in this section is observed directly in production, since it involves heavy loading. Mainly, Spring post-commits hooks hold the database connection open until they finish. Adding time-consuming tasks in a post-commit hook will keep the connection open after commit, and under a heavy load, will lead to connection pool starvation. Apparently, you may think that the connection acquisition takes a lot of time.
Description: This application is a proof of concept for using Spring post-commit hooks.
Key points:
- Avoid time-consuming tasks in post-commits since the database connection will remain open until this code finishes.
Source code can be found here.
Item 44: How to Exploit Spring Projections (DTOs) and Join Unrelated Entities in Hibernate 5.1+
Hibernate 5.1 introduced explicit joins on unrelated entities. The syntax and behavior are similar to SQL JOIN statements.
Description: This application is a proof of concept for using Spring Projections (DTOs) and join unrelated entities. Hibernate 5.1 introduced explicit joins on unrelated entities and the syntax and behavior are similar to SQL JOIN statements.
Key points:
- Define several entities (e.g.,
Patient
andClinic
unrelated entities) - Populate the database with some test data (e.g. check the file,
resources/data-mysql.sql
) - Write interfaces (projections) that contain getters for the columns that should be fetched from the database (e.g.
PatientNameAndMedicalHistoryDto
) - Write joins queries using JPQL/SQL, for example:
- Query all patients names and medical history with no current treatment (
localhost:8080/allPatientsNameAndMedicalHistoryNoTreatmentInnerJoinJpql
)
- Query all patients names and medical history with no current treatment (
Source code can be found here.
Item 45: Why Avoid Lombok @EqualsAndHashCode in Entities
Lombok is a very popular and useful library these days. Nevertheless, pay attention that Lombok@EqualsAndHashCode
on entities can cause serious issues.
Description: Entities should implementequals()
andhashCode()
as shown here. The main idea is that Hibernate requires that an entity is equal to itself across all its state transitions (transient, attached, detached, and removed). Using Lombok@EqualsAndHashCode
will not respect this requirement.
Key points:
AVOID THESE APPROACHES
- Using Lombok default behavior of
@EqualsAndHashCode
(entity:LombokDefaultProduct
, test:LombokDefaultEqualsAndHashCodeTest
) - Using Lombok
@EqualsAndHashCode
with Primary Key only (entity:LombokIdProduct
, test:LombokEqualsAndHashCodeWithIdOnlyTest
) - Rely on default
equals()
andhashCode()
(entity:DefaultProduct
, test:DefaultEqualsAndHashCodeTest
) - Implement
equals()
andhashCode()
based only on Primary Key (entity:IdProduct
, test:IdEqualsAndHashCodeTest
)
PREFER THESE APPROACHES
- Rely on
@NaturalId
(entity:NaturalIdProduct
, test:NaturalIdEqualsAndHashCodeTest
) - Rely on Primary Key (entity:
GoodProduct
, test:GoodEqualsAndHashCodeTest
)
Good implementation ofequals()
and hashCode()
:
Source code can be found here.
Item 46: How to Avoid LazyInitializationException Via JOIN FETCH
If you never got the famousLazyInitializationException,
then you never used Hibernate 🙂 But if you got it and you fixed it by switching fromLAZY
toEAGER
, then this item is for you.
Description: Typically, when we get aLazyInitializationException
, we tend to modify the relationship fetching type fromLAZY
toEAGER
. That is bad! This is a code smell. The best way to avoid this exception is to rely onJOIN FETCH
+ DTOs (if needed). This application is aJOIN FETCH
example with no DTOs (it fetches entities in a singleSELECT
query). But, based on the DTOs examples from above, you can easily adapt it to use DTOs as well.
Key points:
- Define two related entities (e.g.
Category
andProduct
in a one-to-many lazy bidirectional relationship) - Write a JPQL
JOIN FETCH
to fetch a category including products - Write a JPQL
JOIN FETCH
to fetch all products including categories
Output sample:
Source code can be found here.
Item 47: How to Merge Entity Collections
Merging collection correctly is not an easy job!
Description: This is a Spring Boot example based on the following article. This is a functional-style implementation of Vlad’s example. It is highly recommended that you read this article.
Key points:
- Remove the existing database rows that are no longer found in the incoming collection
- Update the existing database rows, which can be found in the incoming collection
- Add the rows found in the incoming collection, which cannot be found in the current database snapshot
Source code can be found here.
Item 48: How to Delay Connection Acquisition as Needed (Hibernate 5.2.10)
Acquiring a database connection and not use it immediately can lead to performance penalties. Mainly, holding a connection without interacting with the database is a bad idea, since somebody else may need a connection and is waiting for one to be available.
Description: This is a Spring Boot example that exploits the Hibernate 5.2.10 capability of delaying the connection acquisition as needed. Normally, a database connection is acquired immediately after calling a method annotated with @Transactional
. If this method contains some time-consuming tasks before the first SQL statement, then the connection is held for nothing. But, Hibernate 5.2.10 allows us to delay the connection acquisition as needed. This example relies on HikariCP as the default connection pool for Spring Boot.
Key points:
- Set
spring.datasource.hikari.auto-commit=false
inapplication.properties
- Set
spring.jpa.properties.hibernate.connection.provider_disables_autocommit=true
inapplication.properties
Output sample:
Source code can be found here.
Item 49: How to Fetch Primary Keys Via Hibernate hi/lo Algorithm
Typically, we don’t care too much of how the Primary Keys are generated or obtained. Or, if we care, then we decide to go with theSEQUENCE
generator as a very convenient, flexible, and efficient approach. Nevertheless, each sequence value requires a database round trip, and this cannot be good for performance. Thehi/lo
algorithm is an optimization algorithm for generating sequences of identifiers.
Description: This is a Spring Boot example of using thehi/lo
algorithm for fetching 1000 PKs in 10 database roundtrips for batching 1000 inserts in batches of 10 inserts.
Key points:
- Use the
SEQUENCE
generator type (e.g., in PostgreSQL) - Configure the
hi/lo
algorithm as inPlayer.java
entity
Output sample:
Source code can be found here.
Item 50: How to Write an Efficient Bidirectional @ManyToMany Association
Do you need a many-to-many table relationship and you don’t want to map it via two bidirectional@OneToMany
associations? You prefer to stick with a bidirectional@ManyToMany
? OK, then do it as efficient as possible.
Description: This is a Spring Boot proof of concept for writing an efficient bidirectional@ManyToMany
association.
Key points:
- We use two entities,
Tournament
andPlayer
, and a tournament can have multiple players and a player can participate in multiple tournaments
Output sample:
Source code can be found here.
Item 51: Prefer Set Instead of List in @ManyToMany Relationships
UsingList
instead ofSet
in@ManyToMany
may lead to more SQLs than expected (e.g., for remove operations) and, therefore, to less performance.
Description: This is a Spring Boot example of removing rows in case of a bidirectional@ManyToMany
using aList
and aSet
. The conclusion is thatSet
is much better! This applies to unidirectional as well!
Key points:
- using
Set
is much more efficient thanList
Output sample:
Source code can be found here.
Connect any Java based application to your SaaS data. Over 100+ Java-based data source connectors.
Like This Article? Read More From DZone
Comment (0)
Opinions expressed by DZone contributors are their own.
Java Partner Resources
Java Partner Resources
- {{ node.blurb }}
{{ editionName }}
{{ parent.title || parent.header.title}}
{{ parent.tldr }}
{{ parent.linkDescription }}
{{ $dialog.title }}
{{ message }}