Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Best Performance Practices for Hibernate 5 and Spring Boot 2 (Part 2)

DZone's Guide to

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.

· Java Zone ·
Free Resource

Download Microservices for Java Developers: A hands-on introduction to frameworks and containers. Brought to you in partnership with Red Hat.

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 inpom.xmlthe dependencies specific to Blaze-Persistence
  • Configure Blaze-Persistence,CriteriaBuilderFactory, and EntityViewManager
  • Write an entity view via an interface in the Blaze-Persistence fashion
  • Write a Spring-centric repository by extendingEntityViewRepository
  • Call a method of this repository, such asfindAll(),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@ElementCollectiondoesn't have a Primary Key
  • An@ElementCollectionis 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:

How @ElementCollection Without @OrderColumn Works

Source code can be found here.

Item 34: How @ElementCollection With @OrderColumn Works

Inserts and deletes that affect@ElementCollectionwith@OrderColumnare 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@OrderColumncan 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@ElementCollectiondoesn't have a Primary Key
  • An@ElementCollectionis mapped in a separate database table
  • Prefer @ElementCollectionwith@OrderColumnwhen 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:

How @ElementCollection With @OrderColumn Works

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 theConnectionas 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:

How to Avoid Lazy Initialization Caused by Open Session In View Anti-Pattern

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.,TournamentandPlayerin a bidirectional@OneToManyrelationship)
  • 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.,PatientandClinicunrelated 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)

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@EqualsAndHashCodeon 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@EqualsAndHashCodewill not respect this requirement.

Key points:
AVOID THESE APPROACHES

  • Using Lombok default behavior of@EqualsAndHashCode(entity:LombokDefaultProduct, test:LombokDefaultEqualsAndHashCodeTest)
  • Using Lombok@EqualsAndHashCodewith Primary Key only (entity:LombokIdProduct, test:LombokEqualsAndHashCodeWithIdOnlyTest)
  • Rely on defaultequals()andhashCode()(entity:DefaultProduct, test:DefaultEqualsAndHashCodeTest)
  • Implementequals()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():

Image title

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 fromLAZYtoEAGER, then this item is for you.

Description: Typically, when we get aLazyInitializationException, we tend to modify the relationship fetching type fromLAZYtoEAGER. 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 FETCHexample with no DTOs (it fetches entities in a singleSELECTquery). 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.CategoryandProductin a one-to-many lazy bidirectional relationship)
  • Write a JPQLJOIN FETCHto fetch a category including products
  • Write a JPQLJOIN FETCHto fetch all products including categories

Output sample:

How to Avoid LazyInitializationException Via JOIN FETCH

How to Avoid LazyInitializationException Via JOIN FETCH

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:

  • Setspring.datasource.hikari.auto-commit=falseinapplication.properties
  • Setspring.jpa.properties.hibernate.connection.provider_disables_autocommit=truein application.properties

Output sample:

How to Delay Connection Acquisition as Needed (Hibernate 5.2.10)

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 theSEQUENCEgenerator 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/loalgorithm is an optimization algorithm for generating sequences of identifiers.

Description: This is a Spring Boot example of using thehi/loalgorithm for fetching 1000 PKs in 10 database roundtrips for batching 1000 inserts in batches of 10 inserts.

Key points:

  • Use theSEQUENCEgenerator type (e.g., in PostgreSQL)
  • Configure thehi/loalgorithm as inPlayer.javaentity

Output sample:

Image title

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@OneToManyassociations? 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,TournamentandPlayer, and a tournament can have multiple players and a player can participate in multiple tournaments

Output sample:

How to Write an Efficient Bidirectional @ManyToMany Association

Source code can be found here.

Item 51: Prefer Set Instead of List in @ManyToMany Relationships

UsingListinstead ofSetin@ManyToManymay 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@ManyToManyusing aListand aSet. The conclusion is thatSetis much better! This applies to unidirectional as well!

Key points:

  • usingSetis much more efficient thanList

Output sample:

Prefer Set Instead of List in @ManyToMany Relationships

Source code can be found here.

If you liked the article, you might also like the book.

Download Building Reactive Microservices in Java: Asynchronous and Event-Based Application Design. Brought to you in partnership with Red Hat

Topics:
java ,spring ,spring boot ,hibernate 5 ,spring boot 2 ,code ,performance

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}