Hibernate-SpringBoot

Collection of 300+ best practices for Java persistence performance in Spring Boot applications

View on GitHub

If you just want to level up to Spring Boot 4 with Hibernate 7 then follow this repo

Tweet

Best Performance Practices Hibernate 5/6 & Spring Boot 2

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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.

Hibernate & Spring Boot Samples

  1. How To Store UTC Timezone In MySQL

Description: This application is a sample of how to store date, time, and timestamps in UTC time zone. The second setting, useLegacyDatetimeCode is needed only for MySQL. Otherwise, set only hibernate.jdbc.time_zone.

Key points:


  1. View Binding/Extracted Params Via Log4J 2

Description: View the prepared statement binding/extracted parameters via Log4J 2 logger setting.

Key points:

Output example:


  1. How To View Query Details Via DataSource-Proxy Library

Description: View the query details (query type, binding parameters, batch size, execution time, etc) via DataSource-Proxy

Key points:

Output example:


  1. Batch Inserts via saveAll(Iterable<S> entities) in MySQL

Description: Batch inserts via SimpleJpaRepository#saveAll(Iterable<S> entities) method in MySQL

Key points:


  1. Batch Inserts Via EntityManager (MySQL)

Description: This application is a sample of batching inserts via EntityManager in MySQL. This way you can easily control the flush() and clear() cycles of the Persistence Context (1st Level Cache) inside the current transaction. This is not possible via Spring Boot, saveAll(Iterable<S> entities), since this method executes a single flush per transaction. Another advantage is that you can call persist() instead of merge() - this is used behind the scene by the SpringBoot saveAll(Iterable<S> entities) and save(S entity).

If you want to execute a batch per transaction (recommended) then check this example.

Key points:

Output example:


  1. How To Batch Inserts Via JpaContext/EntityManager In MySQL

Description: Batch inserts via JpaContext/EntityManager in MySQL.

Key points:

Output example:


  1. How To Exploit Session-Level Batching (Hibernate 5.2 Or Higher) In MySQL

Description: Batch inserts via Hibernate session-level batching (Hibernate 5.2 or higher) in MySQL.

Key points:

Output example:


  1. Direct Fetching Via Spring Data findById(), JPA EntityManager And Hibernate Session

Description: Direct fetching via Spring Data, EntityManager and Hibernate Session examples.

Key points:


  1. DTO Via Spring Data Projections

Note: You may also like to read the recipe, “How To Enrich DTOs With Virtual Properties Via Spring Projections”

Description: Fetch only the needed data from the database via Spring Data Projections (DTO).

Key points:

Note: Using projections is not limited to use query builder mechanism built into Spring Data repository infrastructure. We can fetch projections via JPQL or native queries as well. For example, in this application we use a JPQL.

Output example (select first 2 rows; select only “name” and “age”):


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. How To Use Hibernate Attribute Lazy Loading

Description: By default, the attributes of an entity are loaded eagerly (all at once). But, we can load them lazy 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 avatar lazy. So, the avatar should be loaded on demand.

Key points:

Check as well:
- Default Values For Lazy Loaded Attributes
- Attribute Lazy Loading And Jackson Serialization


  1. How To Populate a Child-Side Parent Association via Proxy

Description: A Hibernate proxy can be useful when a child entity can be persisted with a reference to its parent (@ManyToOne or @OneToOne association). In such cases, fetching the parent entity from the database (execute the SELECT statement) is a performance penalty and a pointless action, because Hibernate can set the underlying foreign key value for an uninitialized proxy.

Key points:

Output example:


  1. How To Quickly Reproduce The N+1 Performance Issue

Description: The N+1 is an issue of lazy fetching (but, eager is not exempt). This application reproduce the N+1 behavior.

Key points:

Output example:


  1. Optimize SELECT DISTINCT Via Hibernate HINT_PASS_DISTINCT_THROUGH Hint

Description: Starting with Hibernate 5.2.2, we can optimize JPQL (HQL) query entites of type SELECT DISTINCT via HINT_PASS_DISTINCT_THROUGH hint. Keep in mind that this hint is useful only for JPQL (HQL) JOIN FETCH-ing queries. Is not useful for scalar queries (e.g., List<Integer>), DTO or HHH-13280. In such cases, the DISTINCT JPQL keyword is needed to be passed to the underlying SQL query. This will instruct the database to remove duplicates from the result set.

Key points:

Output example:


  1. How To Enable Dirty Tracking In A Spring Boot Application

Note: The Hibernate Dirty Checking mechanism is responsible to identify the entitites modifications at flush-time and to trigger the corresponding UPDATE statements in our behalf.

Description: Prior to Hibernate version 5, the Dirty Checking mechanism relies on Java Reflection API for checking every property of every managed entity. Starting with Hibernate version 5, the Dirty Checking mechanism can rely on the Dirty Tracking mechanism (which is the capability of an entity to track its own attributes changes) which requires Hibernate Bytecode Enhancement to be present in the application. The Dirty Tracking mechanism sustain a better performance, especially when you have a relatively large number of entitites.

For Dirty Tracking, during Bytecode Enhancement process, the entity classes bytecode is instrumented by Hibernate by adding a tracker, $$_hibernate_tracker. At flush time, Hibernate will use this tracker to discover the entities changes (each entity tracker will report the changes). This is better than checking every property of every managed entity.

Commonly (by default), the instrumentation takes place at build-time, but it can be configured to take place at runtime or deploy-time as well. It is preferable to take place at build-time for avoiding an overhead in the runtime.

Adding Bytecode Enhancement and enabling Dirty Tracking can be done via a plugin added via Maven or Gradle (Ant can be used as well). We use Maven, therefore we add it in pom.xml.

Key points:

Output example:

The Bytecode Enhancement effect can be seen on Author.class here. Notice how the bytecode was instrumented with $$_hibernate_tracker.


  1. Use Java 8 Optional In Entities And Queries

Description: This application is an example of how is correct to use the Java 8 Optional in entities and queries.

Key points:


  1. The Best Way To Map The @OneToMany Bidirectional Association

Description: This application is a proof of concept of how is correct to implement the bidirectional @OneToMany association from the performance perspective.

Key points:

Note: Pay attention to remove operations, especially to removing child entities. The CascadeType.REMOVE and orphanRemoval=true may produce too many queries. In such scenarios, relying on bulk operations is most of the time the best way to go for deletions.


  1. Query Fetching

Description: This application is an example of how to write a query via JpaRepository, EntityManager and Session.

Key points:


  1. Why And How To Avoid The AUTO Generator Type In Hibernate 5 And MySQL

Description: In MySQL & Hibernate 5, the GenerationType.AUTO generator type will result in using the TABLE generator. This adds a significant performance penalty. Turning this behavior to IDENTITY generator can be obtained by using GenerationType.IDENTITY or the native generator.

Key points:

Output example:


  1. How To Avoid The Redundant save() Call

Description: This application is an example when calling save() for an entity is redundant (not necessary).

Key points:


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. Why To Avoid PostgreSQL (BIG)SERIAL In Batching Inserts Via Hibernate

Description: In PostgreSQL, using GenerationType.IDENTITY will disable insert batching. The (BIG)SERIAL is acting “almost” like MySQL, AUTO_INCREMENT. In this application, we use the GenerationType.SEQUENCE which permits insert batching, and we optimize it via the hi/lo optimization algorithm.

Key points:

Output example:


  1. JPA Inheritance - SINGLE_TABLE

Description: This application is a sample of using JPA Single Table inheritance strategy (SINGLE_TABLE).

Key points:

Output example (below is a single table obtained from 3 entities):


  1. Count and Assert SQL Statements

Description: This application is a sample of counting and asserting SQL statements triggered “behind the scene”. Is very useful to count the SQL statements in order to ensure that your code is not generating more SQL statements that you may think (e.g., N+1 can be easily detected by asserting the number of expected statements).

Key points:

Output example (when the number of expected SQLs is not equal with the reality an exception is thrown):


  1. How To Setup JPA Callbacks

Description: This application is a sample of setting the JPA callbacks (Pre/PostPersist, Pre/PostUpdate, Pre/PostRemove and PostLoad).

Key points:

Output example:


  1. How To Use @MapsId For Sharing Identifier In @OneToOne Relationship

Description: Instead of regular unidirectional/bidirectional @OneToOne better rely on an unidirectional @OneToOne and @MapsId. This application is a proof of concept.

Key points:

Note:


  1. How To Fetch DTO Via SqlResultSetMapping And EntityManager

Description: Fetching more data than needed is prone to performance penalities. Using DTO allows us to extract only the needed data. In this application we rely on SqlResultSetMapping and EntityManager.

Key points:


  1. How To Fetch DTO Via SqlResultSetMapping And NamedNativeQuery

Note: If you want to rely on the {EntityName}.{RepositoryMethodName} naming convention for simply creating in the repository interface methods with the same name as of native named query then skip this application and check this one.

Description: Fetching more data than needed is prone to performance penalities. Using DTO allows us to extract only the needed data. In this application we rely on SqlResultSetMapping, NamedNativeQuery.

Key points:


  1. How To Fetch DTO Via javax.persistence.Tuple And Native SQL

Description: Fetching more data than needed is prone to performance penalities. Using DTO allows us to extract only the needed data. In this application we rely on javax.persistence.Tuple and native SQL.

Key points:


  1. How To Fetch DTO via javax.persistence.Tuple and JPQL

Description: Fetching more data than needed is prone to performance penalities. Using DTO allows us to extract only the needed data. In this application we rely on javax.persistence.Tuple and JPQL.

Key points:


  1. How To Fetch DTO Via Constructor Expression and JPQL

Description: Fetching more data than needed is prone to performance penalities. Using DTO allows us to extract only the needed data. In this application we rely on Constructor Expression and JPQL.

Key points:

See also:
How To Fetch DTO Via Constructor And Spring Data Query Builder Mechanism


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. How To Fetch DTO Via ResultTransformer And Native SQL

Description: Fetching more data than needed is prone to performance penalties. Using DTO allows us to extract only the needed data. In this application we rely on Hibernate, ResultTransformer and native SQL.

Key points:


  1. How To Fetch DTO Via ResultTransformer and JPQL

Description: Fetching more data than needed is prone to performance penalties. Using DTO allows us to extract only the needed data. In this application we rely on Hibernate, ResultTransformer and JPQL.

Key points:


  1. How To Fetch DTO Via Blaze-Persistence Entity Views

Description: Fetching more data than needed is prone to performance penalities. Using DTO allows us to extract only the needed data. In this application we rely on Blaze-Persistence entity views.

Key points:


  1. How Regular @ElementCollection (Without @OrderColumn) Works

Description: This application reveals the possible performance penalties of using @ElementCollection. In this case, without @OrderColumn. As you can see in the next item (34) adding @OrderColumn can mitigate some performance penalties.

Key points:

Output example:


  1. How @ElementCollection With @OrderColumn Works

Description: This application reveals the performance penalties of using @ElementCollection. In this case, with @OrderColumn. But, as you can see in this application (in comparison with item 33), by adding @OrderColumn can mitigate some performance penalties when operations takes 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:

Output example:


  1. How To Avoid Lazy Initialization Issues Caused By Disabling Open Session In View Via Explicit (Default) Values

Note: Before reading this item try to see if Hibernate5Module is not what you are looking for.

Description: The Open-Session in View anti-pattern is activated by default in SpringBoot. Now, imagine a lazy association (e.g., @OneToMany) between two entities, Author and Book (an author has associated more books). Next, a REST controller endpoint fetches an Author without the associated Book. But, the View (more precisely, Jackson), forces the lazy loading of the associated Book as well. Since OSIV will supply the already opened Session, the proxies initializations take place successfully. The solution to avoid this performance penalty starts by disabling the OSIV. Further, explicitly initialize the un-fetched lazy associations. This way, the View will not force lazy loading.

Key points:

NOTE: If OSIV is enabled, the developer can still initialize the un-fetched lazy associations manually as long as he does this outside of a transaction to avoid flushing. But, why is this working? Since the Session is open, why the manually initialization of the associations of a managed entity doesn’t trigger the flush? The answer can be found in the documentation of OpenSessionInViewFilter which specifies that: 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).


  1. How To Use Spring Projections(DTO) And Inner Joins

Description: This application is a proof of concept for using Spring Projections(DTO) and inner joins written via JPQL and native SQL (for MySQL).

Key points:


  1. How To Use Spring Projections(DTO) And Left Joins

Description: This application is a proof of concept for using Spring Projections(DTO) and left joins written via JPQL and native SQL (for MySQL).

Key points:


  1. How To Use Spring Projections(DTO) And Right Joins

Description: This application is a proof of concept for using Spring Projections(DTO) and right joins written via JPQL and native SQL (for MySQL).

Key points:


  1. How To Use Spring Projections(DTO) And Inclusive Full Joins (PostgreSQL)

Description: This application is a proof of concept for using Spring Projections(DTO) and inclusive full joins written via JPQL and native SQL (for PostgreSQL).

Key points:


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. How To Use Spring Projections(DTO) And Exclusive Left Joins

Description: This application is a proof of concept for using Spring Projections(DTO) and exclusive left joins written via JPQL and native SQL (for MySQL).

Key points:


  1. How To Use Spring Projections(DTO) And Exclusive Right Joins

Description: This application is a proof of concept for using Spring Projections(DTO) and exclusive right joins written via JPQL and native SQL (for MySQL).

Key points:


  1. How To Use Spring Projections(DTO) And Exclusive Full Joins (PostgreSQL)

Description: This application is a proof of concept for using Spring Projections(DTO) and exclusive full joins written via JPQL and native SQL (for PostgreSQL).

Key points:


  1. Why You Should Avoid Time-Consuming Tasks In Spring Boot Post-Commit Hooks

Description: This application is a proof of concept for using Spring post-commit hooks and how they may affect the persistence layer performance.

Key points:


  1. How To Exploit Spring Projections(DTO) And Join Unrelated Entities In Hibernate 5.1+

Description: This application is a proof of concept for using Spring Projections (DTO) and join unrelated entities. Hibernate 5.1 introduced explicit joins on unrelated entities and the syntax and behaviour are similar to SQL JOIN statements.

Key points:


  1. Why To Avoid Lombok @EqualsAndHashCode And @Data In Entities And How To Override equals() And hashCode()

Description: Entities should implement equals() and hashCode() as 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 (or @Data) will not respect this requirment.

Key points:
AVOID THESE APPROACHES

PREFER THESE APPROACHES


  1. How To Avoid LazyInitializationException Via JOIN FETCH

See also:

Description: Typically, when we get a LazyInitializationException we tend to modify the association fetching type from LAZY to EAGER. That is very bad! This is a code smell. Best way to avoid this exception is to rely on JOIN FETCH (if you plan to modify the fetched entities) or JOIN + DTO (if the fetched data is only read). JOIN FETCH allows associations to be initialized along with their parent objects using a single SELECT. This is particularly useful for fetching associated collections.

This application is a JOIN FETCH example for avoiding LazyInitializationException.

Key points:

Output example:


  1. How To Merge Entity Collections

Description: This is a Spring Boot example based on the following article. Is a functional implementation of the Vlad’s example. It is highly recommended to read that article.

Key points:


  1. How To Delay Connection Acquisition As Needed (Hibernate 5.2.10)

Description: This is a Spring Boot example that exploits Hibernate 5.2.10 capability of delaying the connection acquisition as needed. By default, in resource-local mode, a database connection is aquried 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 hold open for nothing. But, Hibernate 5.2.10 allows us to delay the connection acquisition as needed. This example rely on HikariCP as the default connection pool for Spring Boot.

Key points:

Output example:


  1. How To Generate Sequences Of Identifiers Via Hibernate hi/lo Algorithm

Note: If systems external to your application need to insert rows in your tables then don’t rely on hi/lo algorithm since, in such cases, it may cause errors resulted from generating duplicated identifiers. Rely on pooled or pooled-lo algorithms (optimizations of hi/lo).

Description: This is a Spring Boot example of using the hi/lo algorithm for generating 1000 identifiers in 10 database roundtrips for batching 1000 inserts in batches of 30.

Key points:

Output example:


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. The Best Way To Implement A Bidirectional @ManyToMany Association

Description: This application is a proof of concept of how it is correct to implement the bidirectional @ManyToMany association from the performance perspective.

Key points:


  1. Prefer Set Instead of List in @ManyToMany Associations

Description: This is a Spring Boot example of removing rows in case of a bidirectional @ManyToMany using List, respectively Set. The conclusion is that Set is much better! This applies to unidirectional as well!

Key points:

Output example:


  1. How To View Query Details Via log4jdbc

Description: View the query details via log4jdbc.

Key points:

Output sample:


  1. How To View Binding Params Via TRACE

Description: View the prepared statement binding/extracted parameters via TRACE.

Key points:

Output sample:


  1. How To Store java.time.YearMonth As Integer Or Date Via Hibernate Types Library

Description: Hibernate Types is a set of extra types not supported by default in Hibernate Core. One of these types is java.time.YearMonth. This is a Spring Boot application that uses Hibernate Type to store this YearMonth in a MySQL database as integer or date.

Key points:

Output example:


  1. How To Execute SQL Functions In JPQL Query

Note: Using SQL functions in the WHERE part (not in the SELECT part) of query in JPA 2.1 can be done via function() as here.

Description: Trying to use SQL functions (standard or defined) in JPQL queries may result in exceptions if Hibernate will not recognize them and cannot parse the JPQL query. For example, the MySQL, concat_ws function is not recognized by Hibernate. This application is a Spring Boot application based on Hibernate 5.3, that registers the concat_ws function via MetadataBuilderContributor and inform Hibernate about it via, metadata_builder_contributor property. This example uses @Query and EntityManager as well, so you can see two use cases.

Key points:

Output example:


  1. Log Slow Queries Via DataSource-Proxy

Description: This application is a sample of logging only slow queries via DataSource-Proxy. A slow query is a query that has an execution time bigger than a specificed threshold in milliseconds.

Key points:

Output example:


  1. Offset Pagination - Trigger SELECT COUNT Subquery And Return Page<dto>

Description: This application fetches data as Page<dto> via Spring Boot offset pagination. Most of the time, the data that should be paginated is read-only data. Fetching the data into entities should be done only if we plan to modify that data, therefore, fetching read only data as Page<entity> is not preferable since it may end up in a significant performance penalty. The SELECT COUNT triggered for counting the total number of records is a subquery of the main SELECT. Therefore, there will be a single database roundtrip instead of two (typically, there is one query needed for fetching the data and one for counting the total number of records).

Key points:


  1. Offset Pagination - Trigger SELECT COUNT Subquery And Return List<dto>

Description: This application fetches data as List<dto> via Spring Boot offset pagination. Most of the time, the data that should be paginated is read-only data. Fetching the data into entities should be done only if we plan to modify that data, therefore, fetching read only data as List<entity> is not preferable since it may end up in a significant performance penalty. The SELECT COUNT triggered for counting the total number of records is a subquery of the main SELECT. Therefore, there will be a single database roundtrip instead of two (typically, there is one query needed for fetching the data and one for counting the total number of records).

Key points:


  1. How To Customize HikariCP Settings Via Properties

If you use the spring-boot-starter-jdbc or spring-boot-starter-data-jpa “starters”, you automatically get a dependency to HikariCP

Note: The best way to tune the connection pool parameters consist in using Flexy Pool by Vlad Mihalcea. Via Flexy Pool you can find the optim settings that sustain high-performance of your connection pool.

Description: This is a kickoff application that set up HikariCP via application.properties only. The jdbcUrl is set up for a MySQL database. For testing purposes, the application uses an ExecutorServicefor simulating concurrent users. Check the HickariCP report revealing the connection pool status.

Key points:

Output sample:


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. How To Customize HikariCP Settings Via Properties And DataSourceBuilder

If you use the spring-boot-starter-jdbc or spring-boot-starter-data-jpa “starters”, you automatically get a dependency to HikariCP

Note: The best way to tune the connection pool parameters consist in using Flexy Pool by Vlad Mihalcea. Via Flexy Pool you can find the optim settings that sustain high-performance of your connection pool.

Description: This is a kickoff application that set up HikariCP via DataSourceBuilder. The jdbcUrl is set up for a MySQL database. For testing purposes, the application uses an ExecutorService for simulating concurrent users. Check the HickariCP report revealing the connection pool status.

Key points:

Output sample:


  1. Running a SpringBoot Application Under Payara Server Using a Payara Data Source (JDBC Resource and Connection Pool)

This application is detailed in this DZone article.


  1. How To Customize BoneCP Settings Via Properties And DataSourceBuilder

Note: The best way to tune the connection pool parameters consist in using Flexy Pool by Vlad Mihalcea. Via Flexy Pool you can find the optim settings that sustain high-performance of your connection pool.

Description: This is a kickoff application that set up BoneCP via DataSourceBuilder. The jdbcUrl is set up for a MySQL database. For testing purposes, the application uses an ExecutorService for simulating concurrent users.

Key points:

Output sample:


  1. How To Customize ViburDBCP Settings Via Properties And DataSourceBuilder

Note: The best way to tune the connection pool parameters consist in using Flexy Pool by Vlad Mihalcea. Via Flexy Pool you can find the optim settings that sustain high-performance of your connection pool.

Description: This is a kickoff application that set up ViburDBCP via DataSourceBuilder. The jdbcUrl is set up for a MySQL database. For testing purposes, the application uses an ExecutorService for simulating concurrent users.

Key points:

Output sample:


  1. How To Customize C3P0 Settings Via Properties And DataSourceBuilder

Note: The best way to tune the connection pool parameters consist in using Flexy Pool by Vlad Mihalcea. Via Flexy Pool you can find the optim settings that sustain high-performance of your connection pool.

Description: This is a kickoff application that set up C3P0 via DataSourceBuilder. The jdbcUrl is set up for a MySQL database. For testing purposes, the application uses an ExecutorService for simulating concurrent users.

Key points:

Output sample:


  1. How To Customize DBCP2 Settings Via Properties And DataSourceBuilder

Note: The best way to tune the connection pool parameters consist in using Flexy Pool by Vlad Mihalcea. Via Flexy Pool you can find the optim settings that sustain high-performance of your connection pool.

Description: This is a kickoff application that set up DBCP2 via DataSourceBuilder. The jdbcUrl is set up for a MySQL database. For testing purposes, the application uses an ExecutorService for simulating concurrent users.

Key points:


  1. How To Customize Tomcat Settings Via Properties And DataSourceBuilder

Note: The best way to tune the connection pool parameters consist in using Flexy Pool by Vlad Mihalcea. Via Flexy Pool you can find the optim settings that sustain high-performance of your connection pool.

Description: This is a kickoff application that set up Tomcat via DataSourceBuilder. The jdbcUrl is set up for a MySQL database. For testing purposes, the application uses an ExecutorService for simulating concurrent users.

Key points:

Output sample:


  1. How To Configure Two Data Sources With Two Connection Pools

Note: The best way to tune the connection pool parameters consist in using Flexy Pool by Vlad Mihalcea. Via Flexy Pool you can find the optim settings that sustain high-performance of your connection pool.

Description: This is a kickoff application that uses two data sources (two MySQL databases, one named authorsdb and one named booksdb) with two connection pools (each database uses its own HikariCP connection pool with different settings). Based on the above items is pretty easy to configure two connection pools from two different providers as well.

Key points:

Output sample:


  1. How To Provide a Fluent API Via Setters For Building Entities

Note: If you want yo provide a Fluent API without altering setters then consider this item.

Description: This is a sample application that alter the entities setters methods in order to empower a Fluent API.

Key points:

Fluent API example:


  1. How To Provide a Fluent API Via Additional Methods For Building Entities

Note: If you want yo provide a Fluent API by altering setters then consider this item.

Description: This is a sample application that add in entities additional methods (e.g., for setName, we add name) methods in order to empower a Fluent API.

Key points:

Fluent API example:


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. How To Implement Slice<T> findAll()

Most probably this is all you want: How To Fetch Slice<entity>/Slice<dto> Via fetchAll/fetchAllDto

Some implementations of Slice<T> findAll():

Story: Spring Boot provides an offset based built-in paging mechanism that returns a Page or Slice. Each of these APIs represents a page of data and some metadata. The main difference is that Page contains the total number of records, while Slice can only tell if there is another page available. For Page, Spring Boot provides a findAll() method capable to take as arguments a Pageable and/or a Specification or Example. In order to create a Page that contains the total number of records, this method triggers an SELECT COUNT extra-query next to the query used to fetch the data of the current page. This can be a performance penalty since the SELECT COUNT query is triggered every time we request a page. In order to avoid this extra-query, Spring Boot provides a more relaxed API, the Slice API. Using Slice instead of Page removes the need of this extra SELECT COUNT query and returns the page (records) and some metadata without the total number of records. So, while Slice doesn’t know the total number of records, it still can tell if there is another page available after the current one or this is the last page. The problem is that Slice work fine for queries containing the SQL, WHERE clause (including those that uses the query builder mechanism built into Spring Data), but it doesn’t work for findAll(). This method will still return a Page instead of Slice therefore the SELECT COUNT query is triggered for Slice<T> findAll(...);.

Description: This is a suite of samples applications that provides different versions of a Slice<T> findAll(...) method. We have from a minimalist implementation that relies on a hardcoded query as: "SELECT e FROM " + entityClass.getSimpleName() + " e"; (this recipe), to a custom implementation that supports sorting, specification, lock mode and query hints to an implementation that relies on extending SimpleJpaRepository.

Key points:


  1. Offset Pagination - Trigger COUNT(*) OVER And Return List<dto>

Description: Typically, in offset pagination, there is one query needed for fetching the data and one for counting the total number of records. But, we can fetch this information in a single database rountrip via a SELECT COUNT subquery nested in the main SELECT. Even better, for databases vendors that support Window Functions there is a solution relying on COUNT(*) OVER() as in this application that uses this window function in a native query against MySQL 8. So, prefer this one instead of SELECT COUNT subquery.

Key points:

Example:


  1. How To Implement Keyset Pagination in Spring Boot

Description: When we rely on an offset paging we have the performance penalty induced by throwing away n records before reached the desired offset. Larger n leads to a significant performance penalty. When we have a large n is better to rely on keyset pagination which maintain a “constant” time for large datasets. In order to understand how bad offset can perform please check this article:

Screenshot from that article (offset pagination):

Need to know if there are more records?
By its nature, keyset doesn’t use a SELECT COUNT to fetch the number of total records. But, with a little tweak, we can easily say if there are more records, therefore to show a button of type Next Page. Mainly, if you need such a thing then consider this application whose climax is listed below:

public AuthorView fetchNextPage(long id, int limit) {
     List<Author> authors = authorRepository.fetchAll(id, limit + 1);

     if (authors.size() == (limit + 1)) {
          authors.remove(authors.size() - 1);
          return new AuthorView(authors, true);
     }

     return new AuthorView(authors, false);
}

Or, like this (rely on Author.toString() method):

public Map<List<Author>, Boolean> fetchNextPage(long id, int limit) {
     List<Author> authors = authorRepository.fetchAll(id, limit + 1);

     if(authors.size() == (limit + 1)) {
          authors.remove(authors.size() -1);
          return Collections.singletonMap(authors, true);
     }

     return Collections.singletonMap(authors, false);
}

A Previous Page button can be implemented easily based on the first record.

Key points:


  1. How To Implement Offset Pagination in Spring Boot

Description: This is a classical Spring Boot offset pagination example. However, is not advisable to use this approach in production because of its performance penalties explained further.

When we rely on an offset pagination, we have the performance penalty induced by throwing away n records before reaching the desired offset. Larger n leads to a significant performance penalty. Another penalty is the extra-SELECT needed to count the total number of records. In order to understand how bad offset pagination can perform please check this article. A screenshot from that article is below: Nevertheless, maybe this example is a little bit extreme. For relatively small datasets, offset pagination is not so bad (it is close in performance to keyset pagination), and, since Spring Boot provides built-in support for offset pagination via the Page API, it is very easy to use it. However, depending on the case, we can optimize a little bit the offset pagination as in the following examples:

Fetch a page as a Page:

Fetch a page as a List:

But: If offset pagination is causing you performance issues and you decide to go with keyset pagination then please check here (keyset pagination).

Key points of classical offset pagination:

Examples of classical offset pagination:


  1. How To Optimize Batch Inserts of Parent-Child Relationships In MySQL

Description: Let’s suppose that we have a one-to-many relationship between Author and Book entities. When we save an author, we save his books as well thanks to cascading all/persist. We want to create a bunch of authors with books and save them in the database (e.g., a MySQL database) using the batch technique. By default, this will result in batching each author and the books per author (one batch for the author and one batch for the books, another batch for the author and another batch for the books, and so on). In order to batch authors and books, we need to order inserts as in this application.

Key points: Beside all setting specific to batching inserts in MySQL, we need to set up in application.properties the following property: spring.jpa.properties.hibernate.order_inserts=true

Example without ordered inserts:

Example with ordered inserts:


  1. How To Batch Updates In MySQL

Implementations:

Description: Batch updates in MySQL.

Key points:

Output example for single entity:

Output example for parent-child relationship:


  1. How To Batch Deletes That Don’t Involve Associations In MySQL

Description: Batch deletes that don’t involve associations in MySQL.

Note: Spring deleteAllInBatch() and deleteInBatch() don’t use delete batching and don’t take advantage of automatic optimstic locking mechanism to prevent lost updates (e.g., @Version is ignored). They rely on Query.executeUpdate() to trigger bulk operations. These operations are fast, but Hibernate doesn’t know which entities are removed, therefore, the Persistence Context is not updated accordingly (it’s up to you to flush (before delete) and close/clear (after delete) the Persistence Context accordingly to avoid issues created by unflushed (if any) or outdated (if any) entities). The first one (deleteAllInBatch()) simply triggers a delete from entity_name statement and is very useful for deleting all records. The second one (deleteInBatch()) triggers a delete from entity_name where id=? or id=? or id=? ... statement, therefore, is prone to cause issues if the generated DELETE statement exceedes the maximum accepted size. This issue can be controlled by deleting the data in chunks, relying on IN operator, and so on. Bulk operations are faster than batching which can be achieved via the deleteAll(), deleteAll(Iterable<? extends T> entities) or delete() method. Behind the scene, the two flavors of deleteAll() relies on delete(). The delete()/deleteAll() methods rely on EntityManager.remove() therefore the Persistence Context is synchronized accordingly. Moreover, if automatic optimstic locking mechanism (to prevent lost updates) is enabled then it will be used.

Key points for regular delete batching:

Output example:


  1. How To Batch Deletes In MySQL Via orphanRemoval=true

Description: Batch deletes in MySQL via orphanRemoval=true.

Note: Spring deleteAllInBatch() and deleteInBatch() don’t use delete batching and don’t take advantage of cascading removal, orphanRemoval and automatic optimstic locking mechanism to prevent lost updates (e.g., @Version is ignored). They rely on Query.executeUpdate() to trigger bulk operations. These operations are fast, but Hibernate doesn’t know which entities are removed, therefore, the Persistence Context is not updated accordingly (it’s up to you to flush (before delete) and close/clear (after delete) the Persistence Context accordingly to avoid issues created by unflushed (if any) or outdated (if any) entities). The first one (deleteAllInBatch()) simply triggers a delete from entity_name statement and is very useful for deleting all records. The second one (deleteInBatch()) triggers a delete from entity_name where id=? or id=? or id=? ... statement, therefore, is prone to cause issues if the generated DELETE statement exceedes the maximum accepted size. This issue can be controlled by deleting the data in chunks, relying on IN operator, and so on. Bulk operations are faster than batching which can be achieved via the deleteAll(), deleteAll(Iterable<? extends T> entities) or delete() method. Behind the scene, the two flavors of deleteAll() relies on delete(). The delete()/deleteAll() methods rely on EntityManager.remove() therefore the Persistence Context is synchronized accordingly. If automatic optimstic locking mechanism (to prevent lost updates) is enabled then it will be used. Moreover, cascading removals and orphanRemoval works as well.

Key points for using deleteAll()/delete():


  1. How To Batch Deletes In MySQL Via SQL ON DELETE CASCADE

Description: Batch deletes in MySQL via ON DELETE CASCADE. Auto-generated database schema will contain the ON DELETE CASCADE directive.

Note: Spring deleteAllInBatch() and deleteInBatch() don’t use delete batching and don’t take advantage of cascading removal, orphanRemoval and automatic optimistic locking mechanism to prevent lost updates (e.g., @Version is ignored), but both of them take advantage on ON DELETE CASCADE and are very efficient. They trigger bulk operations via Query.executeUpdate(), therefore, the Persistence Context is not synchronized accordingly (it’s up to you to flush (before delete) and close/clear (after delete) the Persistence Context accordingly to avoid issues created by unflushed (if any) or outdated (if any) entities). The first one simply triggers a delete from entity_name statement, while the second one triggers a delete from entity_name where id=? or id=? or id=? ... statement. For delete in batches rely on deleteAll(), deleteAll(Iterable<? extends T> entities) or delete() method. Behind the scene, the two flavors of deleteAll() relies on delete(). Mixing batching with database automatic actions (ON DELETE CASCADE) will result in a partially synchronized Persistent Context.

Key points:

Output example:


  1. How To Use Hibernate @NaturalId In Spring Boot Style

Alternative implementation: In case that you want to avoid extending SimpleJpaRepository check this implementation.

Description: This is a SpringBoot application that maps a natural business key using Hibernate @NaturalId. This implementation allows us to use @NaturalId as it was provided by Spring.

Key points:


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. How To Set Up P6Spy in Spring Boot

Description: This is a Spring Boot application that uses P6Spy. P6Spy is a framework that enables database data to be seamlessly intercepted and logged with no code changes to the application.

Key points:

Output sample:


  1. How To Retry Transactions After OptimisticLockException Exception (@Version)

Note: Optimistic locking mechanism via @Version works for detached entities as well.

Description: This is a Spring Boot application that simulates a scenario that leads to an optimistic locking exception. When such exception occur, the application retry the corresponding transaction via db-util library developed by Vlad Mihalcea.

Key points:

Output sample:


  1. How To Retry Transaction After OptimisticLockException Exception (Hibernate Version-less Optimistic Locking Mechanism)

Note: Optimistic locking mechanism via Hibernate version-less doesn’t work for detached entities (don’t close the Persistent Context).

Description: This is a Spring Boot application that simulates a scenario that leads to an optimistic locking exception (e.g., in Spring Boot, OptimisticLockingFailureException) via Hibernate version-less optimistic locking. When such exception occur, the application retry the corresponding transaction via db-util library developed by Vlad Mihalcea.

Key points:


  1. How To Enrich DTO With Virtual Properties Via Spring Projections

Note: You may also like to read the recipe, “How To Create DTO Via Spring Data Projections”

Description: This is an application sample that fetches only the needed columns from the database via Spring Data Projections (DTO) and enrich the result via virtual properties.

Key points:

Output example:


  1. How To Use Query Creation Mechanism For JPA To Limit Result Size

Description: Spring Data comes with the query creation mechanism for JPA that is capable to interpret a query method name and convert it into a SQL query in the proper dialect. This is possible as long as we respect the naming conventions of this mechanism. This is an application that exploit this mechanism to write queries that limit the result size. Basically, the name of the query method instructs Spring Data how to add the LIMIT (or similar clauses depending on the RDBMS) clause to the generated SQL queries.

Key points:

Examples:
- List<Author> findFirst5ByAge(int age);
- List<Author> findFirst5ByAgeGreaterThanEqual(int age);
- List<Author> findFirst5ByAgeLessThan(int age);
- List<Author> findFirst5ByAgeOrderByNameDesc(int age);
- List<Author> findFirst5ByGenreOrderByAgeAsc(String genre);
- List<Author> findFirst5ByAgeGreaterThanEqualOrderByNameAsc(int age);
- List<Author> findFirst5ByGenreAndAgeLessThanOrderByNameDesc(String genre, int age);
- List<AuthorDto> findFirst5ByOrderByAgeAsc();
- Page<Author> queryFirst10ByName(String name, Pageable p);
- Slice<Author> findFirst10ByName(String name, Pageable p);

The list of supported keywords is listed below:


  1. How To Generate A Schema Via schema-*.sql In MySQL

Note: As a rule, in real applications avoid generating schema via hibernate.ddl-auto or set it to validate. Use schema-*.sql file or better Flyway or Liquibase migration tools.

Description: This application is an example of using schema-*.sql to generate a schema(database) in MySQL.

Key points:


  1. How To Generate Two Databases Via schema-*.sql And Match Entities To Them Via @Table In MySQL

Note: As a rule, in real applications avoid generating schema via hibernate.ddl-auto or set it to validate. Use schema-*.sql file or better Flyway or Liquibase.

Description: This application is an example of using schema-*.sql to generate two databases in MySQL. The databases are matched at entity mapping via @Table.

Key points:

Output example:


  1. How To Stream Result Set Via Spring Data In MySQL

Note: For web-applications, pagination should be the way to go, not streaming. But, if you choose streaming then keep in mind the golden rule: keep th result set as small as posible. Also, keep in mind that the Execution Plan might not be as efficient as when using SQL-level pagination.

Description: This application is an example of streaming the result set via Spring Data and MySQL. This example can be adopted for databases that fetches the entire result set in a single roundtrip causing performance penalties.

Key points:


  1. How To Migrate MySQL Database Using Flyway - MySQL Database Created Via createDatabaseIfNotExist

Note: For production, don’t rely on hibernate.ddl-auto (or counterparts) to export schema DDL to the database. Simply remove (disable) hibernate.ddl-auto or set it to validate. Rely on Flyway or Liquibase.

Description: This application is an example of migrating a MySQL database via Flyway when the database exists (it is created before migration via MySQL specific parameter, createDatabaseIfNotExist=true).

Key points:


  1. How To Migrate MySQL Database Using Flyway - Database Created Via spring.flyway.schemas

Note: For production, don’t rely on hibernate.ddl-auto (or counterparts) to export schema DDL to the database. Simply remove (disable) hibernate.ddl-auto or set it to validate. Rely on Flyway or Liquibase.

Description: This application is an example of migrating a MySQL database when the database is created by Flyway via spring.flyway.schemas. In this case, the entities should be annotated with @Table(schema = "bookstoredb") or @Table(catalog = "bookstoredb"). Here, the database name is bookstoredb.

Key points:

Output of migration history example:


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. How To Auto-Create And Migrate Schemas For Two Data Sources (MySQL and PostgreSQL) Using Flyway

Note: For production don’t rely on hibernate.ddl-auto to create your schema. Remove (disable) hibernate.ddl-auto or set it to validate. Rely on Flyway or Liquibase.

Description: This application is an example of auto-creating and migrating schemas for MySQL and PostgreSQL. In addition, each data source uses its own HikariCP connection pool. In case of MySQL, where schema=database, we auto-create the schema (authorsdb) based on createDatabaseIfNotExist=true. In case of PostgreSQL, where a database can have multiple schemas, we use the default postgres database and auto-create in it the schema, booksdb. For this we rely on Flyway, which is capable to create a missing schema.

Key points:


  1. How To Auto-Create And Migrate Two Schemas In PostgreSQL Using Flyway

Note: For production, don’t rely on hibernate.ddl-auto (or counterparts) to export schema DDL to the database. Simply remove (disable) hibernate.ddl-auto or set it to validate. Rely on Flyway or Liquibase.

Description: This application is an example of auto-creating and migrating two schemas in PostgreSQL using Flyway. In addition, each data source uses its own HikariCP connection pool. In case of PostgreSQL, where a database can have multiple schemas, we use the default postgres database and auto-create two schemas, authors and books. For this we rely on Flyway, which is capable to create the missing schemas.

Key points:


  1. How To JOIN FETCH an @ElementCollection

Description: This application is an example applying JOIN FETCH to fetch an @ElementCollection.

Key points:


  1. How To Map An Entity To a Query (@Subselect) in a Spring Boot Application

Note: Consider using @Subselect only if using DTO, DTO and extra queries, or map a database view to an entity is not a solution.

Description: This application is an example of mapping an entity to a query via Hibernate, @Subselect. Mainly, we have two entities in a bidirectional one-to-many association. An Author has wrote several Book. The idea is to write a read-only query to fetch from Author only some fields (e.g., DTO), but to have the posibility to call getBooks() and fetch the Book in a lazy manner as well. As you know, a classic DTO cannot be used, since such DTO is not managed and we cannot navigate the associations (don’t support any managed associations to other entities). Via Hibernate @Subselect we can map a read-only and immutable entity to a query. This time, we can lazy navigate the associations.

Key points:


  1. How To Use Hibernate Soft Deletes In A Spring Boot Application

Description: This application is an example of using Hibernate soft deletes in a Spring Boot application.

Key points:

Output example:


  1. How To Programmatically Customize HikariCP Settings Via DataSourceBuilder

If you use the spring-boot-starter-jdbc or spring-boot-starter-data-jpa “starters”, you automatically get a dependency to HikariCP

Note: The best way to tune the connection pool parameters consist in using Flexy Pool by Vlad Mihalcea. Via Flexy Pool you can find the optim settings that sustain high-performance of your connection pool.

Description: This is a kickoff application that set up HikariCP via DataSourceBuilder. The jdbcUrl is set up for a MySQL database. For testing purposes, the application uses an ExecutorService for simulating concurrent users. Check the HickariCP report revealing the connection pool status.

Key points:


  1. How To Setup Spring Data JPA Auditing

Description: Auditing is useful for maintaining history records. This can later help us in tracking user activities.

Key points:


  1. Hibernate Envers Auditing (spring.jpa.hibernate.ddl-auto=create)

Description: Auditing is useful for maintaining history records. This can later help us in tracking user activities.

Key points:


  1. Attributes Lazy Loading Via Subentities

Description: By default, the attributes of an entity are loaded eager (all at once). This application is an alternative to How To Use Hibernate Attribute Lazy Loading from here. This application uses a base class to isolate the attributes that should be loaded eagerly and subentities (entities that extends the base class) for isolating the attributes that should be loaded on demand.

Key points:

Run the following requests (via BookstoreController):

Check as well:


  1. DTO Via Constructor And Spring Data Query Builder Mechanism

Description: Fetching more data than needed is prone to performance penalities. Using DTO allows us to extract only the needed data. In this application we rely on constructor and Spring Data Query Builder Mechanism.

Key points:

See also:
Dto Via Constructor Expression and JPQL


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. How To Page The Result Set of a JOIN

Description: Using JOIN is very useful for fetching DTOs (data that is never modified, not in the current or subsequent requests). For example, consider two entities, Author and Book in a lazy-bidirectional @OneToMany association. And, we want to fetch a subset of columns from the parent table (author) and a subset of columns from the child table (book). This job is a perfect fit for JOIN which can pick up columns from different tables and build a raw result set. This way we fetch only the needed data. Moreover, we may want to serve the result set in pages (e.g., via LIMIT). This application contains several approaches for accomplishing this task with offset pagination.

Key points:


  1. LEFT JOIN FETCH

See also:

Description: Let’s assume that we have two entities engaged in a one-to-many (or many-to-many) lazy bidirectional (or unidirectional) relationship (e.g., Author has more Book). And, we want to trigger a single SELECT that fetches all Author and the corresponding Book. This is a job for JOIN FETCH which is converted behind the scene into a INNER JOIN. Being an INNER JOIN, the SQL will return only Author that have Book. If we want to return all Author, including those that doesn’t have Book, then we can rely on LEFT JOIN FETCH. Similar, we can fetch all Book, including those with no registered Author. This can be done via LEFT JOIN FETCH or LEFT JOIN.

Key points:


  1. JOIN VS. JOIN FETCH

See also:

Description: This is an application meant to reveal the differences between JOIN and JOIN FETCH. The important thing to keep in mind is that, in case of LAZY fetching, JOIN will not be capable to initialize the associated collections along with their parent objects using a single SQL SELECT. On the other hand, JOIN FETCH is capable to accomplish this kind of task. But, don’t underestimate JOIN, because JOIN is the proper choice when we need to combine/join the columns of two (or more) tables in the same query, but we don’t need to initialize the associated collections on the returned entity (e.g., very useful for fetching DTO).

Key points:

Notice that:


  1. Entity Inside Spring Projection

Description: If, for some reason, you need an entity in your Spring projection (DTO), then this application shows you how to do it via an example. In this case, there are two entities, Author and Book, involved in a lazy bidirectional one-to-many association (it can be other association as well, or even no materialized association). And, we want to fetch in a Spring projection the authors as entities, Author, and the title of the books.

Key points:


  1. Entity Inside Spring Projection (no association)

Description: If, for some reason, you need an entity in your Spring projection (DTO), then this application shows you how to do it via an example. In this case, there are two entities, Author and Book, that have no materialized association between them, but, they share the genre attribute. We use this attribute to join authors with books via JPQL. And, we want to fetch in a Spring projection the authors as entities, Author, and the title of the books.

Key points:


  1. Avoid Entity In DTO Via Constructor Expression (no association)

Description: Let’s assume that we have two entities, Author and Book. There is no materialized association between them, but, both entities shares an attribute named, genre. We want to use this attribute to join the tables corresponding to Author and Book, and fetch the result in a DTO. The result should contain the Author entity and only the title attribute from Book. Well, when you are in a scenario as here, it is strongly advisable to avoid fetching the DTO via constructor expression. This approach cannot fetch the data in a single SELECT, and is prone to N+1. Way better than this consists of using Spring projections, JPA Tuple or even Hibernate ResultTransformer. These approaches will fetch the data in a single SELECT. This application is a DON’T DO THIS example. Check the number of queries needed for fetching the data. In place, do it as here: Entity Inside Spring Projection (no association).


  1. How To DTO an @ElementCollection

Description: This application is an example of fetching a DTO that includes attributes from an @ElementCollection.

Key points:


  1. Ordering The Set Of Associated Entities In @ManyToMany Association Via @OrderBy

Description: In case of @ManyToMany association, we always should rely on Set (not on List) for mapping the collection of associated entities (entities of the other parent-side). Why? Well, please see Prefer Set Instead of List in @ManyToMany Relationships. But, is well-known that HashSet doesn’t have a predefined entry order of elements. If this is an issue then this application relies on @OrderBy which adds an ORDER BY clause in the SQL statement. The database will handle the ordering. Further, Hibernate will preserve the order via a LinkedHashSet.

This application uses two entities, Author and Book, involved in a lazy bidirectional many-to-many relationship. First, we fetch a Book by title. Further, we call getAuthors() to fetch the authors of this book. The fetched authors are ordered descending by name. The ordering is done by the database as a result of adding @OrderBy("name DESC"), and is preserved by Hibernate.

Key points:

Note: Alternatively, we can use @OrderColumn. This gets materialized in an additional column in the junction table. This is needed for maintaining a permanent ordering of the related data.


  1. Versioned Optimistic Locking And Detached Entities Sample

Description: This is a sample application that shows how versioned (@Version) optimistic locking and detached entity works. Running the application will result in an optimistic locking specific exception (e.g., the Spring Boot specific, OptimisticLockingFailureException).

Key points:


  1. How To Simulate OptimisticLockException Shaped Via @Version

Note: Optimistic locking via @Version works for detached entities as well.

Description: This is a Spring Boot application that simulates a scenario that leads to an optimistic locking exception. So, running the application should end up with a Spring specific ObjectOptimisticLockingFailureException exception.

Key points:


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. How To Retry Transaction Via TransactionTemplate After OptimisticLockException Exception (@Version)

Note: Optimistic locking via @Version works for detached entities as well.

Description: This is a Spring Boot application that simulates a scenario that leads to an optimistic locking exception. When such exception occurs, the application retry the corresponding transaction via db-util library developed by Vlad Mihalcea.

Key points:


  1. How To Simulate OptimisticLockException In Version-less Optimistic Locking

Note: Version-less optimistic locking doesn’t work for detached entities (do not close the Persistence Context).

Description: This is a Spring Boot application that simulates a scenario that leads to an optimistic locking exception. So, running the application should end up with a Spring specific ObjectOptimisticLockingFailureException exception.

Key points:


  1. How To Retry Transaction Via TransactionTemplate After OptimisticLockException Shaped Via Hibernate Version-less Optimistic Locking Mechanism

Note: Version-less optimistic locking doesn’t work for detached entities (do not close the Persistence Context).

Description: This is a Spring Boot application that simulates a scenario that leads to an optimistic locking exception. When such exception occur, the application retry the corresponding transaction via db-util library developed by Vlad Mihalcea.

Key points:


  1. HTTP Long Conversation Via Versioned Optimistic Locking And Detached Entities In The HTTP Session

Description: This is a sample application that shows how to take advantage of versioned optimistic locking and detached entities in HTTP long conversations. The climax consists of storing the detached entities across multiple HTTP requests. Commonly, this can be accomplished via HTTP session.

Key points:

Sample output (check the message caused by optimistic locking exception):


  1. Filter Association Via Hibernate @Where

Note: Rely on this approach only if you simply cannot use JOIN FETCH WHERE or @NamedEntityGraph.

Description: This application is a sample of using Hibernate @Where for filtering associations.

Key points:


  1. Batch Inserts In Spring Boot Style

Description: Batch inserts (in MySQL) in Spring Boot style.

Key points:

Output example:


  1. Offset Pagination - Trigger COUNT(*) OVER And Return Page<entity> Via Extra Column

Description: Typically, in offset pagination, there is one query needed for fetching the data and one for counting the total number of records. But, we can fetch this information in a single database rountrip via a SELECT COUNT subquery nested in the main SELECT. Even better, for databases vendors that support Window Functions there is a solution relying on COUNT(*) OVER() as in this application that uses this window function in a native query against MySQL 8. So, prefer this one instead of SELECT COUNT subquery.This application fetches data as Page<entity> via Spring Boot offset pagination, but, if the fetched data is read-only, then rely on Page<dto> as here.

Key points:


  1. Offset Pagination - Trigger SELECT COUNT Subquery And Return List<entity> Via Extra Column

Description: This application fetches data as List<entity> via Spring Boot offset pagination. The SELECT COUNT triggered for counting the total number of records is a subquery of the main SELECT. Therefore, there will be a single database roundtrip instead of two (typically, one query is needed for fetching the data and one for counting the total number of records).

Key points:


  1. Offset Pagination - Trigger SELECT COUNT Subquery And Return List<projection> That Maps Entities And The Total Number Of Records Via Projection

Description: This application fetches data as List<projection> via Spring Boot offset pagination. The projection maps the entity and the total number of records. This information is fetched in a single database rountrip because the SELECT COUNT triggered for counting the total number of records is a subquery of the main SELECT. Therefore, there will be a single database roundtrip instead of two (typically, there is one query needed for fetching the data and one for counting the total number of records). Use this approch only if the fetched data is not read-only. Otherwise, prefer List<dto> as here.

Key points:


  1. Offset Pagination - Trigger COUNT(*) OVER And Return List<entity> Via Extra Column

Description: Typically, in offset pagination, there is one query needed for fetching the data and one for counting the total number of records. But, we can fetch this information in a single database rountrip via a SELECT COUNT subquery nested in the main SELECT. Even better, for databases vendors that support Window Functions there is a solution relying on COUNT(*) OVER() as in this application that uses this window function in a native query against MySQL 8. So, prefer this one instead of SELECT COUNT subquery.This application fetches data as List<entity> via Spring Boot offset pagination, but, if the fetched data is read-only, then rely on List<dto> as here.

Key points:


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. Offset Pagination - Trigger SELECT COUNT Subquery And Return Page<entity> Via Extra Column

Description: This application fetches data as Page<entity> via Spring Boot offset pagination. Use this only if the fetched data will be modified. Otherwise, fetch Page<dto> as here. The SELECT COUNT triggered for counting the total number of records is a subquery of the main SELECT. Therefore, there will be a single database roundtrip instead of two (typically, there is one query needed for fetching the data and one for counting the total number of records).

Key points:


  1. Offset Pagination - Trigger SELECT COUNT Subquery And Return Page<projection> That Maps Entities And The Total Number Of Records Via Projection

Description: This application fetches data as Page<projection> via Spring Boot offset pagination. The projection maps the entity and the total number of records. This information is fetched in a single database rountrip because the SELECT COUNT triggered for counting the total number of records is a subquery of the main SELECT.

Key points:


  1. Offset Pagination - Trigger COUNT(*) OVER And Return Page<dto>

Description: Typically, in offset pagination, there is one query needed for fetching the data and one for counting the total number of records. But, we can fetch this information in a single database rountrip via a SELECT COUNT subquery nested in the main SELECT. Even better, for databases vendors that support Window Functions there is a solution relying on COUNT(*) OVER() as in this application that uses this window function in a native query against MySQL 8. So, prefer this one instead of SELECT COUNT subquery. This application return a Page<dto>.

Key points:

Example:


  1. How To Fetch Slice<entity>/Slice<dto> Via fetchAll/fetchAllDto

Story: Spring Boot provides an offset based built-in paging mechanism that returns a Page or Slice. Each of these APIs represents a page of data and some metadata. The main difference is that Page contains the total number of records, while Slice can only tell if there is another page available. For Page, Spring Boot provides a findAll() method capable to take as arguments a Pageable and/or a Specification or Example. In order to create a Page that contains the total number of records, this method triggers an SELECT COUNT extra-query next to the query used to fetch the data of the current page . This can be a performance penalty since the SELECT COUNT query is triggered every time we request a page. In order to avoid this extra-query, Spring Boot provides a more relaxed API, the Slice API. Using Slice instead of Page removes the need of this extra SELECT COUNT query and returns the page (records) and some metadata without the total number of records. So, while Slice doesn’t know the total number of records, it still can tell if there is another page available after the current one or this is the last page. The problem is that Slice work fine for queries containing the SQL, WHERE clause (including those that uses the query builder mechanism built into Spring Data), but it doesn’t work for findAll(). This method will still return a Page instead of Slice therefore the SELECT COUNT query is triggered for Slice<T> findAll(...);.

Workaround: The trick is to simply define a method named fetchAll() that uses JPQL and Pageable to return Slice<entity>, and a method named fetchAllDto() that uses JPQL and Pageable as well to return Slice<dto>. So, avoid naming the method findAll().

Usage example:
public Slice<Author> fetchNextSlice(int page, int size) {
    return authorRepository.fetchAll(PageRequest.of(page, size, new Sort(Sort.Direction.ASC, "age")));
}

public Slice<AuthorDto> fetchNextSliceDto(int page, int size) {
    return authorRepository.fetchAllDto(PageRequest.of(page, size, new Sort(Sort.Direction.ASC, "age")));
}


  1. How To Use Spring Projections(DTOs) And Inclusive Full Joins (MySQL)

Description: This application is a proof of concept for using Spring Projections(DTO) and inclusive full joins written in native SQL (for MySQL).

Key points:


  1. How To Declare Immutable Entities And Store Them In Second Level Cache (e.g., EhCache)

Description: This application is a sample of declaring an immutable entity. Moreover, the immutable entity will be stored in Second Level Cache via EhCache implementation.

Key points of declaring an immutable entity:


  1. How To Programmatically Customize HikariCP Settings Via DataSourceBuilder

If you use the spring-boot-starter-jdbc or spring-boot-starter-data-jpa “starters”, you automatically get a dependency to HikariCP

Note: The best way to tune the connection pool parameters consist in using Flexy Pool by Vlad Mihalcea. Via Flexy Pool you can find the optim settings that sustain high-performance of your connection pool.

Description: This is a kickoff application that set up HikariCP via DataSourceBuilder. The jdbcUrl is set up for a MySQL database. For testing purposes, the application uses an ExecutorService for simulating concurrent users. Check the HickariCP report revealing the connection pool status.

Key points:

Output sample:


  1. How To Use Hibernate @NaturalIdCache For Skipping The Entity Identifier Retrieval

Description: This is a SpringBoot - MySQL application that maps a natural business key using Hibernate @NaturalId. This implementation allows us to use @NaturalId as it was provided by Spring. Moreover, this application uses Second Level Cache (EhCache) and @NaturalIdCache for skipping the entity identifier retrieval from the database.

Key points:

Output sample (for MySQL with IDENTITY generator, @NaturalIdCache and @Cache):


  1. How To Calculate Non-Persistent Property via JPA @PostLoad

Description: This application is an example of calculating a non-persistent property of an entity based on the persistent entity attributes. In this case, we will use JPA, @PostLoad.

Key points:


  1. How To Calculate Entity Persistent Property Via Hibernate @Generated

Description: This application is an example of calculating an entity persistent property at INSERT and/or UPDATE time via Hibernate, @Generated.

Key points:

Calculate at INSERT time:

Calculate at INSERT and UPDATE time:

Further, apply:

Method 1:

Method 2:

Note: In production, you should not rely on columnDefinition. You should disable hibernate.ddl-auto (by omitting it) or set it to validate, and add the SQL query expression in CREATE TABLE (in this application, check the discount column in CREATE TABLE, file schema-sql.sql). Nevertheless, not even schema-sql.sql is ok in production. The best way is to rely on Flyway or Liquibase.


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. How To Calculate Non-Persistent Property via Hibernate @Formula

Description: This application is an example of calculating a non-persistent property of an entity based on the persistent entity attributes. In this case, we will use Hibernate, @Formula.

Key points:


  1. How To Add created, createdBy, lastModified And lastModifiedBy In Entities Via Hibernate

Note: The same thing can be obtained via Spring Data JPA auditing as here.

Description: This application is an example of adding in an entity the fields, created, createdBy, lastModified and lastModifiedBy via Hibernate support. These fields will be automatically generated/populated.

Key points:


  1. Hibernate Envers Auditing (schema-mysql.sql)

Description: Auditing is useful for maintaining history records. This can later help us in tracking user activities.

Key points:


  1. How To Programmatically Setup Flyway And MySQL DataSource

Note: For production, don’t rely on hibernate.ddl-auto (or counterparts) to export schema DDL to the database. Simply remove (disable) hibernate.ddl-auto or set it to validate. Rely on Flyway or Liquibase.

Description: This application is a kickoff for setting Flyway and MySQL DataSource programmatically.

Key points:


  1. How To Migrate PostgreSQL Database Using Flyway - Use The Default Database postgres And Schema public

Note: For production, don’t rely on hibernate.ddl-auto (or counterparts) to export schema DDL to the database. Simply remove (disable) hibernate.ddl-auto or set it to validate. Rely on Flyway or Liquibase.

Description: This application is an example of migrating a PostgreSQL database via Flyway for the default database postgres and schema public.

Key points:


  1. How To Migrate Schema Using Flyway In PostgreSQL - Use The Default Database postgres And Schema Created Via spring.flyway.schemas

Note: For production, don’t rely on hibernate.ddl-auto (or counterparts) to export schema DDL to the database. Simply remove (disable) hibernate.ddl-auto or set it to validate. Rely on Flyway or Liquibase.

Description: This application is an example of migrating a schema (bookstore) created by Flyway via spring.flyway.schemas in the default postgres database. In this case, the entities should be annotated with @Table(schema = "bookstore").

Key points:


  1. How To Programmatically Setup Flyway And PostgreSQL DataSource

Note: For production, don’t rely on hibernate.ddl-auto (or counterparts) to export schema DDL to the database. Simply remove (disable) hibernate.ddl-auto or set it to validate. Rely on Flyway or Liquibase.

Description: This application is a kickoff for setting Flyway and PostgreSQL DataSource programmatically.

Key points:


  1. How To Auto-Create And Migrate Two Databases In MySQL Using Flyway

Note: For production, don’t rely on hibernate.ddl-auto (or counterparts) to export schema DDL to the database. Simply remove (disable) hibernate.ddl-auto or set it to validate. Rely on Flyway or Liquibase.

Description: This application is an example of auto-creating and migrating two databases in MySQL using Flyway. In addition, each data source uses its own HikariCP connection pool. In case of MySQL, where a database is the same thing with schema, we create two databases, authorsdb and booksdb.

Key points:


  1. Hibernate hi/lo Algorithm And External Systems Issue

Description: This is a Spring Boot sample that exemplifies how the hi/lo algorithm may cause issues when the database is used by external systems as well. Such systems can safely generate non-duplicated identifiers (e.g., for inserting new records) only if they know about the hi/lo presence and its internal work. So, better rely on pooled or pooled-lo algorithm which doesn’t cause such issues.

Key points:

Output sample: Running this application should result in the following error:
ERROR: duplicate key value violates unique constraint "author_pkey"
Detail: Key (id)=(2) already exists.


  1. How To Generate Sequences Of Identifiers Via Hibernate pooled Algorithm

Note: Rely on pooled-lo or pooled especially if, beside your application, external systems needs to insert rows in your tables. Don’t rely on hi/lo since, in such cases, it may cause errors resulted from generating duplicated identifiers.

Description: This is a Spring Boot example of using the pooled algorithm. The pooled is an optimization of hi/lo. This algorithm fetched from the database the current sequence value as the top boundary identifier (the current sequence value is computed as the previous sequence value + increment_size). This way, the application will use in-memory identifiers generated between the previous top boundary exclusive (aka, lowest boundary) and the current top boundary inclusive.

Key points:

Conclusion: In contrast to the classical hi/lo algorithm, the Hibernate pooled algorithm doesn’t cause issues to external systems that wants to interact with our tables. In other words, external systems can concurrently insert rows in the tables relying on pooled algorithm. Nevertheless, old versions of Hibernate can raise exceptions caused by INSERT statements triggered by external systems that uses the lowest boundary as identifier. This is a good reason to update to Hibernate latest versions (e.g., Hibernate 5.x), which have fixed this issue.


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. How To Generate Sequences Of Identifiers Via Hibernate pooled-lo Algorithm

Note: Rely on pooled-lo or pooled especially if, beside your application, external systems needs to insert rows in your tables. Don’t rely on hi/lo since, in such cases, it may cause errors resulted from generating duplicated identifiers.

Description: This is a Spring Boot example of using the pooled-lo algorithm. The pooled-lo is an optimization of hi/lo similar with pooled. Only that, the strategy of this algorithm fetches from the database the current sequence value and use it as the in-memory lowest boundary identifier. The number of in-memory generated identifiers is equal to increment_size.

Key points:


  1. Fetching Associations In Batches Via @BatchSize

Description: This application uses Hibernate specific @BatchSize at class/entity-level and collection-level. Consider Author and Book entities invovled in a bidirectional-lazy @OneToMany association.

Note: Fetching associated collections in the same query with their parent can be done via JOIN FETCH or entity graphs as well. Fetching children with their parents in the same query can be done via JOIN FETCH, entity graphs and JOIN as well.

Key points:


  1. How To Use Entity Graphs (@NamedEntityGraph) In Spring Boot

Note: In a nutshell, entity graphs (aka, fetch plans) is a feature introduced in JPA 2.1 that help us to improve the performance of loading entities. Mainly, we specify the entity’s related associations and basic fields that should be loaded in a single SELECT statement. We can define multiple entity graphs for the same entity and chain any number of entities and even use sub-graphs to create complex fetch plans. To override the current FetchType semantics there are properties that can be set:

Fetch Graph (default), javax.persistence.fetchgraph
The attributes present in attributeNodes are treated as FetchType.EAGER. The remaining attributes are treated as FetchType.LAZY regardless of the default/explicit FetchType.

Load Graph, javax.persistence.loadgraph
The attributes present in attributeNodes are treated as FetchType.EAGER. The remaining attributes are treated according to their specified or default FetchType.

Nevertheless, the JPA specs doesn’t apply in Hibernate for the basic (@Basic) attributes.. More details here.

Description: This is a sample application of using entity graphs in Spring Boot.

Key points:


  1. How To Use Entity Sub-graphs In Spring Boot

Note: In a nutshell, entity graphs (aka, fetch plans) is a feature introduced in JPA 2.1 that help us to improve the performance of loading entities. Mainly, we specify the entity’s related associations and basic fields that should be loaded in a single SELECT statement. We can define multiple entity graphs for the same entity and chain any number of entities and even use sub-graphs to create complex fetch plans. To override the current FetchType semantics there are properties that can be set:

Fetch Graph (default), javax.persistence.fetchgraph
The attributes present in attributeNodes are treated as FetchType.EAGER. The remaining attributes are treated as FetchType.LAZY regardless of the default/explicit FetchType.

Load Graph, javax.persistence.loadgraph
The attributes present in attributeNodes are treated as FetchType.EAGER. The remaining attributes are treated according to their specified or default FetchType.

Nevertheless, the JPA specs doesn’t apply in Hibernate for the basic (@Basic) attributes.. More details here.

Description: This is a sample application of using entity sub-graphs in Spring Boot. There is one example based on @NamedSubgraph and one based on the dot notation (.) in an ad-hoc entity graph.

Key points:

Using @NamedSubgraph

Using the dot notation (.)


  1. How To Define Ad-Hoc Entity Graphs In Spring Boot

Note: In a nutshell, entity graphs (aka, fetch plans) is a feature introduced in JPA 2.1 that help us to improve the performance of loading entities. Mainly, we specify the entity’s related associations and basic fields that should be loaded in a single SELECT statement. We can define multiple entity graphs for the same entity and chain any number of entities and even use sub-graphs to create complex fetch plans. To override the current FetchType semantics there are properties that can be set:

Fetch Graph (default), javax.persistence.fetchgraph
The attributes present in attributeNodes are treated as FetchType.EAGER. The remaining attributes are treated as FetchType.LAZY regardless of the default/explicit FetchType.

Load Graph, javax.persistence.loadgraph
The attributes present in attributeNodes are treated as FetchType.EAGER. The remaining attributes are treated according to their specified or default FetchType.

Nevertheless, the JPA specs doesn’t apply in Hibernate for the basic (@Basic) attributes.. More details here.

Description: This is a sample application of defining ad-hoc entity graphs in Spring Boot.

Key points:


  1. How To Use Entity Graphs For @Basic Attributes In Hibernate And Spring Boot

Note: In a nutshell, entity graphs (aka, fetch plans) is a feature introduced in JPA 2.1 that help us to improve the performance of loading entities. Mainly, we specify the entity’s related associations and basic fields that should be loaded in a single SELECT statement. We can define multiple entity graphs for the same entity and chain any number of entities and even use sub-graphs to create complex fetch plans. To override the current FetchType semantics there are properties that can be set:

Fetch Graph (default), javax.persistence.fetchgraph
The attributes present in attributeNodes are treated as FetchType.EAGER. The remaining attributes are treated as FetchType.LAZY regardless of the default/explicit FetchType.

Load Graph, javax.persistence.loadgraph
The attributes present in attributeNodes are treated as FetchType.EAGER. The remaining attributes are treated according to their specified or default FetchType.

Nevertheless, the JPA specs doesn’t apply in Hibernate for the basic (@Basic) attributes. In other words, by default, attributes are annotated with @Basic which rely on the default fetch policy. The default fetch policy is FetchType.EAGER. These attributes are also loaded in case of fetch graph even if they are not explicitly specified via @NamedAttributeNode. Annotating the basic attributes that should not be fetched with @Basic(fetch = FetchType.LAZY) it is not enough. Both, fetch graph and load graph will ignore these settings as long as we don’t add bytecode enhancement as well.

The main drawback consists of the fact the these basic attributes are fetched LAZY by all other queries (e.g., findById()) not only by the queries using the entity graph, and most probably, you will not want this behavior.

Description: This is a sample application of using entity graphs with @Basic attributes in Spring Boot.

Key points:


  1. How To Implement Soft Deletes Via SoftDeleteRepository In Spring Boot Application

Note: Spring Data built-in support for soft deletes is discussed in DATAJPA-307.

Description: This application is an example of implementing soft deletes in Spring Data style via a repository named, SoftDeleteRepository.

Key points:

Output example:


  1. How To Implement Concurrent Table Based Queue Via SKIP_LOCKED In MySQL 8

Description: This application is an example of how to implement concurrent table based queue via SKIP_LOCKED in MySQL 8. SKIP_LOCKED can skip over locks achieved by other concurrent transactions, therefore is a great choice for implementing job queues. In this application, we run two concurrent transactions. The first transaction will lock the records with ids 1, 2 and 3. The second transaction will skip the records with ids 1, 2 and 3 and will lock the records with ids 4, 5 and 6.

Key points:


  1. How To Implement Concurrent Table Based Queue Via SKIP_LOCKED In PostgreSQL

Description: This application is an example of how to implement concurrent table based queue via SKIP_LOCKED in PostgreSQL. SKIP_LOCKED can skip over locks achieved by other concurrent transactions, therefore is a great choice for implementing job queues. In this application, we run two concurrent transactions. The first transaction will lock the records with ids 1, 2 and 3. The second transaction will skip the records with ids 1, 2 and 3 and will lock the records with ids 4, 5 and 6.

Key points:


  1. JPA Inheritance - JOINED

Description: This application is a sample of JPA Join Table inheritance strategy (JOINED)

Key points:


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. JPA Inheritance - TABLE_PER_CLASS

Description: This application is a sample of JPA Table-per-class inheritance strategy (TABLE_PER_CLASS)

Key points:


  1. JPA Inheritance - @MappedSuperclass

Description: This application is a sample of using the JPA @MappedSuperclass.

Key points:


  1. How To Avoid Lazy Initialization Issues Caused By Disabling Open Session In View Via Hibernate5Module

Note: Hibernate5Module is an add-on module for Jackson JSON processor which handles Hibernate datatypes; and specifically aspects of lazy-loading.

Description: By default, in Spring Boot, the Open Session in View anti-pattern is enabled. Now, imagine a lazy relationship (e.g., @OneToMany) between two entities, Author and Book (an author has associated more books). Next, a REST controller endpoint fetches an Author without the associated Book. But, the View (more precisely, Jackson), forces the lazy loading of the associated Book as well. Since OSIV will supply the already opened Session, the Proxy initializations take place successfully.

Of course, the correct decision is to disable OSIV by setting it to false, but this will not stop Jackson to try to force the lazy initialization of the associated Book entities. Running the code again will result in an exception of type: Could not write JSON: failed to lazily initialize a collection of role: com.bookstore.entity.Author.books, could not initialize proxy - no Session; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.bookstore.entity.Author.books, could not initialize proxy - no Session.

Well, among the Hibernate5Module features we have support for dealing with this aspect of lazy loading and eliminate this exception. Even if OSIV will continue to be enabled (not recommended), Jackson will not use the Session opened via OSIV.

Key points:

Note: The presence of Hibernate5Module instructs Jackson to initialize the lazy associations with default values (e.g., a lazy associated collection will be initialized with null). Hibernate5Module doesn’t work for lazy loaded attributes. For such case consider this item.


  1. How To View Binding Params Via profileSQL=true In MySQL

Description: View the prepared statement binding parameters via profileSQL=true in MySQL.

Key points:

Output sample:


  1. How To Shuffle Small Result Sets

Description: This application is an example of shuffling small results sets. DO NOT USE this technique for large results sets, since is extremely expensive.

Key points:


  1. The Best Way To Remove Parent And Child Entities Via Bulk Deletions

Description: Commonly, deleting a parent and the associated children via CascadeType.REMOVE and/or orphanRemoval=true involved several SQL statements (e.g., each child is deleted in a dedicated DELETE statement). When the number of entities is significant, this is far from being efficient, therefore other approaches should be employed.

Consider Author and Book in a bidirectional-lazy @OneToMany association. This application exposes the best way to delete the parent(s) and the associated children in four scenarios listed below. These approaches relies on bulk deletions, therefore they are not useful if you want the deletions to take advantage of automatic optimistic locking mechanisms (e.g., via @Version):

Best way to delete author(s) and the associated books via bulk deletions when:

Note: The most efficient way to delete all entities via a bulk deletion can be done via the built-in deleteAllInBatch().


  1. How To Bulk Updates

Description: Bulk operations (updates and deletes) are faster than batching, can benefit from indexing, but they have three main drawbacks:

This application provides examples of bulk updates for Author and Book entities (between Author and Book there is a bidirectional lazy @OneToMany association). Both, Author and Book, has a version field.


  1. Why You Should Avoid Unidirectional @OneToMany And Prefer Bidirectional @OneToMany Relationship

Description: As a rule of thumb, unidirectional @OneToMany association is less efficient than the bidirectional @OneToMany or the unidirectional @ManyToOne associations. This application is a sample that exposes the DML statements generated for reads, writes and removal operations when the unidirectional @OneToMany mapping is used.

Key points:


  1. How To Use Subqeries in JPQL WHERE/HAVING Clause

Description: This application is an example of using subqueries in JPQL WHERE clause (you can easily use it in HAVING clause as well).

Key points:
Keep in mind that subqueries and joins queries may or may not be semantically equivalent (joins may returns duplicates that can be removed via DISTINCT).

Even if the Execution Plan is specific to the database, historically speaking joins are faster than subqueries among different databases, but this is not a rule (e.g., the amount of data may significantly influence the results). Of course, do not conclude that subqueries are just a replacement for joins that doesn’t deserve attention. Tuning subqueries can increases their performance as well, but this is an SQL wide topic. So, benchmark! Benchmark! Benchmark!

As a rule of thumb, prefer subqueries only if you cannot use joins, or if you can prove that they are faster than the alternative joins.


  1. How To Execute SQL Functions In WHERE Part Of JPQL Query And JPA 2.1

Note: Using SQL functions in SELECT part (not in WHERE part) of the query can be done as here.

Description: Starting with JPA 2.1, a JPQL query can call SQL functions in the WHERE part via function(). This application is an example of calling the MySQL, concat_ws function, but user defined (custom) functions can be used as well.

Key points:


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. Calling Stored Procedure That Returns A Value

Description: This application is an example of calling a MySQL stored procedure that returns a value (e.g., an Integer).

Key points:


  1. Calling Stored Procedure That Returns A Result Set (Entity And DTO)

Description: This application is an example of calling a MySQL stored procedure that returns a result set. The application fetches entities (e.g., List<Author>) and DTO (e.g., List<AuthorDto>).

Key points:


  1. Calling Stored Procedure That Returns A Result Set Via Native Query

Description: This application is an example of calling a MySQL stored procedure that returns a result set (entity or DTO) via a native query.

Key points:


  1. Calling Stored Procedure That Returns A Result Set Via JdbcTemplate

Note: Most probably you’ll like to process the result set via BeanPropertyRowMapper as here. This is less verbose than the approach used here. Nevertheless, this approach is useful to understand how the result set looks like.

Description: This application is an example of calling a MySQL stored procedure that returns a result set via JdbcTemplate.

Key points:


  1. How To Obtain Auto-Generated Keys

Description: This application is an example of retrieving the database auto-generated primary keys.

Key points:


  1. How To Unproxy A Proxy

Description: A Hibernate proxy can be useful when a child entity can be persisted with a reference to its parent (@ManyToOne or @OneToOne association). In such cases, fetching the parent entity from the database (execute the SELECT statement) is a performance penalty and a pointless action. Hibernate can set the underlying foreign key value for an uninitialized proxy. This topic is discussed here.

A proxy can be unproxied via Hibernate.unproxy(). This method is available starting with Hibernate 5.2.10.

Key points:


  1. How To Convert Boolean To Yes/No Via AttributeConverter

Description: This application is an example of converting a Boolean to Yes/No strings via AttributeConverter. This kind of conversions are needed when we deal with legacy databases that connot be changed. In this case, the legacy database stores the booleans as Yes/No.

Key points:


  1. How Efficient Is Just @OManyToOne

Note: The @ManyToOne association maps exactly to the one-to-many table relationship. The underlying foreign key is under child-side control in unidirectional or bidirectional relationship.

Description: This application shows that using only @ManyToOne is quite efficient. On the other hand, using only @OneToMany is far away from being efficient. Always, prefer bidirectional @OneToMany or unidirectional @ManyToOne. Consider two entities, Author and Book in a unidirectional @ManyToOne relationship.

Key points:


  1. How To Use JOIN FETCH And Pageable Pagination

Description: Trying to combine JOIN FETCH/LEFT JOIN FETCH and Pageable results in an exception of type org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list. This application is a sample of how to avoid this exception.

Key points:

Note: Fixing the above exception will lead to an warning of type HHH000104, firstResult / maxResults specified with collection fetch; applying in memory!. If this warning is a performance issue, and most probably it is, then follow by reading here.


  1. How To Avoid HHH000104 And Use Pagination Of Parent-Child

Description: HHH000104 is a Hibernate warning that tell us that pagination of a result set is tacking place in memory. For example, consider the Author and Book entities in a lazy-bidirectional @OneToMany association and the following query:

@Transactional
@Query(value = "SELECT a FROM Author a LEFT JOIN FETCH a.books WHERE a.genre = ?1",
            countQuery = "SELECT COUNT(a) FROM Author a WHERE a.genre = ?1")
Page<Author> fetchWithBooksByGenre(String genre, Pageable pageable);

Calling fetchWithBooksByGenre() works fine only that the following warning is signaled: HHH000104: firstResult / maxResults specified with collection fetch; applying in memory! Obviously, having pagination in memory cannot be good from performance perspective. This application implement a solution for moving pagination at database-level.

Key points:


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. What @Transactional(readOnly=true) Actually Do

Description: This application is meant to reveal what is the difference between @Transactional(readOnly = false) and @Transactional(readOnly = true). In a nuthsell, readOnly = false (default) fetches entites in read-write mode (managed). Before Spring 5.1, readOnly = true just set FlushType.MANUAL/NEVER, therefore the automatic dirty checking mechanism will not take action since there is no flush. In other words, Hibernate keep in the Persistent Context the fetched entities and the hydrated (loaded) state. By comparing the entity state with the hydrated state, the dirty checking mechanism can decide to trigger UPDATE statements in our behalf. But, the dirty checking mechanism take place at flush time, therefore, without a flush, the hydrated state is kept in Persistent Context for nothing, representing a performance penalty. Starting with Spring 5.1, the read-only mode is propagated to Hibernate, therefore the hydrated state is discarded immediately after loading the entities. Even if the read-only mode discards the hydrated state the entities are still loaded in the Persistent Context, therefore, for read-only data, relying on DTO (Spring projection) is better.

Key points:


  1. Get Transaction Id In MySQL

Description: This application is an example of getting the current database transaction id in MySQL. Only read-write database transactions gets an id in MySQL. Every database has a specific query for getting the transaction id. Here it is a list of these queries.

Key points:


  1. Inspect Persistent Context

Description: This application is a sample of inspecting the Persistent Context content via org.hibernate.engine.spi.PersistenceContext.

Key points:


  1. How To Extract Tables Metadata

Description: This application is an example of using the Hibernate SPI, org.hibernate.integrator.spi.Integrator for extracting tables metadata.

Key points:


  1. How To Map @ManyToOne Relationship To A SQL Query Via The Hibernate @JoinFormula

Description: This application is an example of mapping the JPA @ManyToOne relationship to a SQL query via the Hibernate @JoinFormula annotation. We start with two entities, Author and Book, involved in a unidirectional @ManyToOne relationship. Each book has a price. While we fetch a book by id (let’s call it book A), we want to fetch another book B of the same author whose price is the next smaller price in comparison with book A price.

Key points:


  1. How To Fetch Data From A MySQL Database View

Description: This application is an example of fetching a read-only MySQL database view in a JPA immutable entity.

Key points:


  1. How To Update/Insert/Delete Data From/In A MySQL Database View

Description: This application is an example of updating, inserting and deleting data in a MySQL database view. Every update/insert/delete will automatically update the contents of the underlying table(s).

Key points:


  1. How To Prevent A MySQL Database View From Updating/Inserting Rows That Are Not Visible Through It Via WITH CHECK OPTION

Description: This application is an example of preventing inserts/updates of a MySQL view that are not visible through this view via WITH CHECK OPTION. In other words, whenever you insert or update a row of the base tables through a view, MySQL ensures that the this operation is conformed with the definition of the view.

Key points:


  1. How To Efficiently Assign A Database Temporary Sequence Of Values To Rows

Description: This application is an example of assigning a database temporary sequence of values to rows via the window function, ROW_NUMBER(). This window function is available in almost all databases, and starting with version 8.x is available in MySQL as well.

Key points:

Output sample:


  1. How To Efficiently Finding Top N Rows Of Every Group

Description: This application is an example of finding top N rows of every group.

Key points:

Output sample:


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. How To Implement Pagination Via ROW_NUMBER() Window Function

Description: This application is an example of using ROW_NUMBER() (and COUNT(*) OVER() for counting all elements) window function to implement pagination.

Key points:


  1. Why the @Transactional annotation is being ignored

Description: This application is an example of fixing the case when @Transactional annotation is ignored. Most of the time, this annotation is ignored in the following scenarios:

  1. @Transactional was added to a private, protected or package-protected method
  2. @Transactional was added to a method defined in the same class where it is invoked

Key points:


  1. How To Generate Custom Sequence IDs

Description: This is a Spring Boot example of using the hi/lo algorithm and a custom implementation of SequenceStyleGenerator for generating custom sequence IDs (e.g, A-0000000001, A-0000000002, …).

Key points:


  1. How To Map Clob And Blob To byte[] And String

Description: This application is an example of mapping Clob and Blob as byte[] and String.

Key points:


  1. How To Map To JDBC’s LOB Locators Clob And Blob

Description: This application is an example of mapping to JDBC’s LOB locators Clob and Blob.

Key points:


  1. How To Fetch Certain Subclass From An SINGLE_TABLE Inheritance Hierarchy

Description: This application is a sample of fetching a certain subclass from a SINGLE_TABLE inheritance hierarchy. This is useful when the dedicated repository of the subclass doesn’t automatically add in the WHERE clause a dtype based condition for fetching only the needed subclass.

Key points:


  1. How To Define An Association That Reference @NaturalId

Description: This is a SpringBoot application that defines a @ManyToOne relationship that doesn’t reference a primary key column. It references a Hibernate @NaturalId column.

Key points:


  1. How To Implement Advanced Search Via Specification

Description: This application is an example of implementing an advanced search via Specification API. Mainly, you can give the search filters to a generic Specification and fetch the result set. Pagination is supported as well. You can chain expressions via logical AND and OR to create compound filters. Nevertheless, there is room for extensions to add brackets support (e.g., (x AND y) OR (x AND z)), more operations, conditions parser and so on and forth.

Key points:


  1. How To Create Specification Query Fetch Joins

Description: This application contains two examples of how to define JOIN in Specification to emulate JPQL join-fetch operations.

Key points:


  1. DTO Via Spring Data Projections (Projection Interface In Repository Interface)

Note: You may also like to read the recipe, “How To Enrich DTO With Virtual Properties Via Spring Projections”

Description: Fetch only the needed data from the database via Spring Data Projections (DTO). The projection interface is defined as a static interface (can be non-static as well) in the repository interface.

Key points:

Note: Using projections is not limited to use query builder mechanism built into Spring Data repository infrastructure. We can fetch projections via JPQL or native queries as well. For example, in this application we use a JPQL.

Output example (select first 2 rows; select only “name” and “age”):


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. How To Ensure/Validate That Only One Association Is Non-Null

Description: Consider an entity named Review. This entity defines three @ManyToOne relationships to Book, Article and Magazine. A review can be associated with either a book, a magazine or an article. To validate this constraint, we can rely on Bean Validation as in this application.

Key points:


  1. Quickest Mapping Of Java Enums

Description: This application uses EnumType.ORDINAL and EnumType.STRING for mapping Java enum type to database. As a rule of thumb, strive to keep the data types as small as possible (e.g., for EnumType.ORDINAL use TINYINT/SMALLINT, while for EnumType.STRING use VARCHAR(max_needed_bytes)). Relying on EnumType.ORDINAL should be more efficient but is less expressive than EnumType.STRING.

Key points:


  1. How To Map Java enum To Database Via AttributeConverter

Description: This application maps a Java enum via AttributeConverter. In other words, it maps the enum values HORROR, ANTHOLOGY and HISTORY to the integers 1, 2 and 3 and viceversa. This allows us to set the column type as TINYINT/SMALLINT which is less space-consuming than VARCHAR(9) needed in this case.

Key points:


  1. How To Map Java enum To PostgreSQL enum Type

Description: This application maps a Java enum type to PostgreSQL enum type.

Key points:


  1. How To Map Java enum To PostgreSQL enum Type Via Hibernate Types Library

Description: This application maps a Java enum type to PostgreSQL enum type via Hibernate Types library.

Key points:


  1. How To Handle JSON in MySQL

Description: Hibernate Types is a library of extra types not supported by Hibernate Core by default. This is a Spring Boot application that uses this library to persist JSON data (JSON Java Object) in a MySQL json column and for querying JSON data from the MySQL json column to JSON Java Object. Updates are supported as well.

Key points:


  1. How To Handle JSON in PostgreSQL

Description: Hibernate Types is a library of extra types not supported by Hibernate Core by default. This is a Spring Boot application that uses this library to persist JSON data (JSON Java Object) in a PostgreSQL json column and for querying JSON data from the PostgreSQL json column to JSON Java Object. Updates are supported as well.

Key points:


  1. How To Increment The Version Of The Locked Entity Even If This Entity Was Not Modified OPTIMISTIC_FORCE_INCREMENT

Description: This application is a sample of how OPTIMISTIC_FORCE_INCREMENT works in MySQL. This is useful when you want to increment the version of the locked entity even if this entity was not modified. Via OPTIMISTIC_FORCE_INCREMENT the version is updated (incremented) at the end of the currently running transaction.

Key points:


  1. How To Increment The Version Of The Locked Entity Even If This Entity Was Not Modified PESSIMISTIC_FORCE_INCREMENT

Description: This application is a sample of how PESSIMISTIC_FORCE_INCREMENT works in MySQL. This is useful when you want to increment the version of the locked entity even if this entity was not modified. Via PESSIMISTIC_FORCE_INCREMENT the version is updated (incremented) immediately (the entity version update is guaranteed to succeed immediately after acquiring the row-level lock). The incrementation takes place before the entity is returned to the data access layer.

Key points:

Note: Pay attention to the MySQL dialect: MySQL5Dialect (MyISAM) doesn’t support row-level locking, MySQL5InnoDBDialect (InnoDB) acquires row-level lock via FOR UPDATE (timeout can be set), MySQL8Dialect (InnoDB) acquires row-level lock via FOR UPDATE NOWAIT.


  1. How PESSIMISTIC_READ And PESSIMISTIC_WRITE Works In MySQL

Description: This application is an example of using PESSIMISTIC_READ and PESSIMISTIC_WRITE in MySQL. In a nutshell, each database system defines its own syntax for acquiring shared and exclusive locks and not all databases support both types of locks. Depending on Dialect, the syntax can vary for the same database as well (Hibernate relies on Dialect for chosing the proper syntax). In MySQL, MySQL5Dialect doesn’t support locking, while InnoDB engine (MySQL5InnoDBDialect and MySQL8Dialect) supports shared and exclusive locks as expected.

Key points:


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. How PESSIMISTIC_WRITE Works With UPDATE/INSERT And DELETE Operations

Description: This application is an example of triggering UPDATE, INSERT and DELETE operations in the context of PESSIMISTIC_WRITE locking against MySQL. While UPDATE and DELETE are blocked until the exclusive lock is released, INSERT depends on the transaction isolation level. Typically, even with exclusive locks, inserts are possible (e.g., in PostgreSQL). In MySQL, for the default isolation level, REPEATABLE READ, inserts are prevented against a range of locked entries, but, if we switch to READ_COMMITTED, then MySQL acts as PostgreSQL as well.

Key points:


  1. How To Check That Transaction Timeout And Rollback At Expiration Works As Expected

Note: Do not test transaction timeout via Thread.sleep()! This is not working! Rely on two transactions and exclusive locks or even better rely on SQL sleep functions (e.g., MySQL, SELECT SLEEP(n) seconds, PostgreSQL, SELECT PG_SLEEP(n) seconds). Most RDBMS supports a sleep function flavor.

Description: This application contains several approaches for setting a timeout period for a transaction or query. The timeout is signaled by a specific timeout exception (e.g., .QueryTimeoutException). After timeout, the transaction is rolled back. You can see this in the database (visually or query) and on log via a message of type: Initiating transaction rollback; Rolling back JPA transaction on EntityManager [SessionImpl(... <open>)].

Key points:

Note: If you are using TransactionTemplate then the timeout can be set via TransactionTemplate.setTimeout(n) in seconds.


  1. How To Define A Composite Primary Key Via @Embeddable

Description: This application is a proof of concept of how to define a composite key via @Embeddable and @EmbeddedId. This application uses two entities, Author and Book involved in a lazy bidirectional @OneToMany association. The identifier of Author is composed by name and age via AuthorId class. The identifier of Book is just a regular auto-generated numeric value.

Key points:


  1. How To Define A Composite Primary Key Via @IdClass

Description: This application is a proof of concept of how to define a composite key via @IdClass. This application uses two entities, Author and Book involved in a lazy bidirectional @OneToMany association. The identifier of Author is composed by name and age via AuthorId class. The identifier of Book is just a typical auto-generated numeric value.

Key points:

Note: The @IdClass can be useful when we cannot modify the compsite key class. Otherwise, rely on @Embeddable.


  1. How To Define A Relationship in an @Embeddable Composite Primary Key

Description: This application is a proof of concept of how to define a relationship in an @Embeddable composite key. The composite key is AuthorId and it belongs to the Author class.

Key points:


  1. How To Load Multiple Entities By Id

Description: This is a SpringBoot application that loads multiple entities by id via a @Query based on the IN operator and via the Hibernate 5 MultiIdentifierLoadAccess interface.

Key points:


  1. Fetching All Entity Attributes As Spring Projection (DTO)

Description: This application is a sample of fetching all attributes of an entity (Author) as a Spring projection (DTO). Commonly, a DTO contains a subset of attributes, but, sometimes we need to fetch the whole entity as a DTO. In such cases, we have to pay attention to the chosen approach. Choosing wisely can spare us from performance penalties.

Key points:


  1. How To Efficiently Fetch Spring Projection Including @ManyToOne Or @OneToOne Associations

Description: This application fetches a Spring projection including the @ManyToOne association via different approaches. It can be easily adapted for @OneToOne association as well.

Key points:


  1. Pay Attention To Spring Projections That Include Associated Collections

Description: This application inspect the Persistent Context content during fetching Spring projections that includes collections of associations. In this case, we focus on a @OneToMany association. Mainly, we want to fetch only some attributes from the parent-side and some attributes from the child-side.


  1. Reusing Spring projection

Description: This application is a sample of reusing an interface-based Spring projection. This is useful to avoid defining multiple interface-based Spring projections in order to cover a range of queries that fetches different subsets of fields.

Key points:


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. Dynamic Spring projection

Description: This application is a sample of using dynamic Spring projections.

Key points:


  1. Batch Inserts Via EntityManager With Batch Per Transaction (MySQL)

Description: This application is a sample of batching inserts via EntityManager in MySQL. This way you can easily control the flush() and clear() cycles of the Persistence Context (1st Level Cache) inside the current transaction. This is not possible via Spring Boot, saveAll(Iterable<S> entities), since this method executes a single flush per transaction. Another advantage is that you can call persist() instead of merge() - this is used behind the scene by the SpringBoot saveAll(Iterable<S> entities) and save(S entity).

Moreover, this example commits the database transaction after each batch excecution. This way we avoid long-running transactions and, in case of a failure, we rollback only the failed batch and don’t lose the previous batches. For each batch, the Persistent Context is flushed and cleared, therefore we maintain a thin Persistent Context. This way the code is not prone to memory errors and performance penalties caused by slow flushes.

Key points:

Output example:


  1. How To JDBC Batch a Big JSON File To MySQL Via ForkJoinPool And HikariCP

Description: This is a Spring Boot application that reads a relatively big JSON file (200000+ lines) and inserts its content in MySQL via batching using ForkJoinPool, JdbcTemplate and HikariCP.

Key points:


  1. Batch Inserts In Spring Boot Style Via CompletableFuture

Description: This application is a sample of using CompletableFuture for batching inserts. This CompletableFuture uses an Executor that has the number of threads equal with the number of your computer cores. Usage is in Spring style.


  1. How To Optimize Batch Inserts of Parent-Child Relationships And Batch Per Transaction (MySQL)

Description: Let’s suppose that we have a one-to-many relationship between Author and Book entities. When we save an author, we save his books as well thanks to cascading all/persist. We want to create a bunch of authors with books and save them in the database (e.g., a MySQL database) using the batch technique. By default, this will result in batching each author and the books per author (one batch for the author and one batch for the books, another batch for the author and another batch for the books, and so on). In order to batch authors and books, we need to order inserts as in this application.

Moreover, this example commits the database transaction after each batch excecution. This way we avoid long-running transactions and, in case of a failure, we rollback only the failed batch and don’t lose the previous batches. For each batch, the Persistent Context is flushed and cleared, therefore we maintain a thin Persistent Context. This way the code is not prone to memory errors and performance penalties caused by slow flushes.

Key points:

Example without ordered inserts:

Example with ordered inserts:


  1. Batch Inserts In Spring Boot Style And Batch Per Transaction

Description: Batch inserts (in MySQL) in Spring Boot style. This example commits the database transaction after each batch excecution. This way we avoid long-running transactions and, in case of a failure, we rollback only the failed batch and don’t lose the previous batches.

Key points:

Output example:


  1. IN Clause Parameter Padding

Description: This application is an example of using Hibernate IN cluase parameter padding. This way we can reduce the number of Execution Plans. Mainly, Hibernate is padding parameters as follows:

Key points:


  1. DTO Via Spring Data Class-Based Projections

Description: Fetch only the needed data from the database via Spring Data Projections (DTO). In this case, via class-based projections.

Key points:

Note: Using projections is not limited to use query builder mechanism built into Spring Data repository infrastructure. We can fetch projections via JPQL or native queries as well. For example, in this application we use a JPQL.

Output example (select first 2 rows; select only “name” and “age”):


  1. Session-Level Batching (Hibernate 5.2 or Higher) in MySQL

Description: Batch inserts via Hibernate session-level batching (Hibernate 5.2 or higher) in MySQL. This example commits the database transaction after each batch excecution. This way we avoid long-running transactions and, in case of a failure, we rollback only the failed batch and don’t lose the previous batches. For each batch, the Persistent Context is flushed and cleared, therefore we maintain a thin Persistent Context. This way the code is not prone to memory errors and performance penalties caused by slow flushes.

Key points:

Output example:


  1. Use Read-Only Entity Whenever You Plan To Propagate Entity Changes To The Database In A Future Persistent Context

Description: This application highlights the difference betweeen loading entities in read-write vs. read-only mode. If you plan to modify the entities in a future Persistent Context then fetch them as read-only in the current Persistent Context.

Key points:

Note: If you never plan to modify the fetched result set then use DTO (e.g., Spring projection), not read-only entities.


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. How To Publish Domain Events From Aggregate Root

Note: Domain events should be used with extra-caution! The best practices for using them are revealed in my book, Spring Boot Persistence Best Practices.

Description: Starting with Spring Data Ingalls release publishing domain events by aggregate roots becomes easier. Entities managed by repositories are aggregate roots. In a Domain-Driven Design application, these aggregate roots usually publish domain events. Spring Data provides an annotation @DomainEvents you can use on a method of your aggregate root to make that publication as easy as possible. A method annotated with @DomainEvents is automatically invoked by Spring Data whenever an entity is saved using the right repository. Moreover, Spring Data provides the @AfterDomainEventsPublication annotation to indicate the method that should be automatically called for clearing events after publication. Spring Data Commons comes with a convenient template base class (AbstractAggregateRoot) to help to register domain events and is using the publication mechanism implied by @DomainEvents and @AfterDomainEventsPublication. The events are registered by calling the AbstractAggregateRoot.registerEvent() method. The registered domain events are published if we call one of the save methods (e.g., save()) of the Spring Data repository and cleared after publication.

This is a sample application that relies on AbstractAggregateRoot and its registerEvent() method. We have two entities, Book and BookReview involved in a lazy-bidirectional @OneToMany association. A new book review is saved in CHECK status and a CheckReviewEvent is published. This event handler is responsible to check the review grammar, content, etc and switch the review status from CHECK to ACCEPT or REJECT and propagate the new status to the database. So, this event is registered before saving the book review in CHECK status and is published automatically after we call the BookReviewRepository.save() method. After publication, the event is cleared.

Key points:


  1. How To Use Hibernate Query Plan Cache

Description: This application is an example of testing the Hibernate Query Plan Cache (QPC). Hibernate QPC is enabled by default and, for entity queries (JPQL and Criteria API), the QPC has a size of 2048, while for native queries it has a size of 128. Pay attention to alter these values to accommodate all queries executed by your application. If the number of exectued queries is higher than the QPC size (especially for entity queries) then you will start to experiment performance penalties caused by entity compilation time added for each query execution.

In this application, you can adjust the QPC size in application.properties. Mainly, there are 2 JPQL queries and a QPC of size 2. Switching from size 2 to size 1 will cause the compilation of one JPQL query at each execution. Measuring the times for 5000 executions using a QPC of size 2, respectively 1 reveals the importance of QPC in terms of time.

Key points:


  1. How To Cache Entities And Query Results In Second Level Cache (EhCache)

Description: This is a SpringBoot application that enables Hibernate Second Level Cache and EhCache provider. It contains an example of caching entities and an example of caching a query result.

Key points:


  1. Spring Boot Caching Kickoff

Description: This is a SpringBoot application representing a kickoff application for Spring Boot caching and EhCache.

Key points:


  1. How To Fetch Entity Via SqlResultSetMapping And NamedNativeQuery

Note: If you want to rely on the {EntityName}.{RepositoryMethodName} naming convention for simply creating in the repository interface methods with the same name as of native named query then skip this application and check this one.

Description: This is a sample application of using SqlResultSetMapping, NamedNativeQuery and EntityResult for fetching single entity and multiple entities as List<Object[]>.

Key points:


  1. How To Load Multiple Entities By Id Via Specification

Description: This is a SpringBoot application that loads multiple entities by id via a @Query based on the IN operator and via Specification.

Key points:


  1. How To Fetch DTO Via A Custom ResultTransformer

Description: Fetching more read-only data than needed is prone to performance penalties. Using DTO allows us to extract only the needed data. Sometimes, we need to fetch a DTO made of a subset of properties (columns) from a parent-child association. For such cases, we can use SQL JOIN that can pick up the desired columns from the involved tables. But, JOIN returns an List<Object[]> and most probably you will need to represent it as a List<ParentDto>, where a ParentDto instance has a List<ChildDto>. For such cases, we can rely on a custom Hibernate ResultTransformer. This application is a sample of writing a custom ResultTransformer.

Key points:


  1. How To Efficiently Chunk A Java List

Description: Is a common scenario to have a big List and to need to chunk it in multiple smaller List of given size. For example, if we want to employee a concurrent batch implementation we need to give to each thread a sublist of items. Chunking a list can be done via Google Guava, Lists.partition(List list, int size) method or Apache Commons Collections, ListUtils.partition(List list, int size) method. But, it can be implemented in plain Java as well. This application exposes 6 ways to do it. The trade-off is between the speed of implementation and speed of execution. For example, while the implementation relying on grouping collector is not performing very well, it is quite simple and fast to write it.

Key points:

Time-performance trend graphic for chunking 500, 1_000_000, 10_000_000 and 20_000_000 items in lists of 5 items:


  1. How To Implement Complex Data Integrity Constraints And Rules

Description: Consider the Book and Chapter entities. A book has a maximum accepted number of pages (book_pages) and the author should not exceed this number. When a chapter is ready for review, the author is submitting it. At this point, the publisher should check that the currently total number of pages doesn’t exceed the allowed book_pages:

This kind of checks or constraints are easy to implement via database triggers. This application relies on a MySQL trigger to empower our complex contraint (check_book_pages).

Key points:


  1. How To Check If A Transient Entity Exists In The Database Via Spring Query By Example (QBE)

Description: This application is an example of using Spring Data Query By Example (QBE) to check if a transient entity exists in the database. Consider the Book entity and a Spring controller that exposes an endpoint as: public String checkBook(@Validated @ModelAttribute Book book, ...). Beside writting an explicit JPQL, we can rely on Spring Data Query Builder mechanism or, even better, on Query By Example (QBE) API. In this context, QBE API is quite useful if the entity has a significant number of attributes and:

Key points:

Note: Do not conclude that Query By Example (QBE) defines only the exists() method. Check out all methods here.


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. Best Way To Use @Transactional

Description: This application is meant to highlight that the best place to use @Transactional for user defined query-methods is in repository interface, and afterwards, depending on situation, on service-methods level.

Key points:


  1. How To Use JPA JOINED Inheritance Strategy And Visitor Design Pattern

Description: This application is an example of using JPA JOINED inheritance strategy and Visitor pattern.

Key points:


  1. How To Use JPA JOINED Inheritance Strategy And Strategy Design Pattern

Description: This application is an example of using JPA JOINED inheritance strategy and Strategy pattern.

Key points:


  1. How Spring Transaction Propagation Work

Description: This folder holds several applications that shows how each Spring transaction propagation works.

Key points:


  1. How To Use JPA GenerationType.AUTO And UUID Identifiers

Description: This application is an example of using the JPA GenerationType.AUTO for assigning automatically UUID identifiers.

Key points:


  1. How To Manually Assign UUID Identifiers

Description: This application is an example of manually assigning UUID identifiers.

Key points:


  1. How To Use Hibernate uuid2 For Generating UUID Identifiers

Description: This application is an example of using the Hibernate RFC 4122 compliant UUID generator, uuid2.

Key points:


  1. How Hibernate Session-Level Repeatable Reads Works

Description: This Spring Boot application is a sample that reveals how Hibernate session-level repeatable reads works. Persistence Context guarantees session-level repeatable reads. Check out how it works.

Key points:

Note: For a detailed explanation of this application consider my book, Spring Boot Persistence Best Practices


  1. Why To Avoid Hibernate-specific hibernate.enable_lazy_load_no_trans

Description: This application is an example of using Hibernate-specific hibernate.enable_lazy_load_no_trans. Check out the application log to see how transactions and database connections are used.

Key points:


  1. The Best Way To Clone Entities

Description: This application is an example of cloning entities. The best way to achieve this goal relies on copy-constructors. This way we can control what we copy. Here we use a bidirectional-lazy @ManyToMany association between Author and Book.

Key points:


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. How To Include In The UPDATE Statement Only The Modified Columns Via Hibernate @DynamicUpdate

Description: This application is an example of using the Hibernate-specific, @DynamicUpdate. By default, even if we modify only a subset of columns, the triggered UPDATE statements will include all columns. By simply annotating the corresponding entity at class-level with @DynamicUpdate the generated UPDATE statement will include only the modified columns.

Key points:


  1. How To Log Spring Data JPA Repository Query-Method Execution Time

Description: This application is an example of logging execution time for a repository query-method.

Key points:


  1. How To Take Control Before/After Transaction Commits/Completes Via Callbacks

Description: This application is an example of using the TransactionSynchronizationAdapter for overriding beforeCommit(), beforeCompletion(), afterCommit() and afterCompletion() callbacks globally (application-level) and at method-level.

Key points:


  1. How To Fetch DTO Via SqlResultSetMapping And NamedNativeQuery Using {EntityName}.{RepositoryMethodName} Naming Convention

Description: Fetching more data than needed is prone to performance penalities. Using DTO allows us to extract only the needed data. In this application we rely on SqlResultSetMapping, NamedNativeQuery and the {EntityName}.{RepositoryMethodName} naming convention. This convention allows us to create in the repository interface methods with the same name as of native named query.

Key points:


  1. How To Fetch Entity Via SqlResultSetMapping And NamedNativeQuery Using {EntityName}.{RepositoryMethodName} Naming Convention

Description: This is a sample application of using SqlResultSetMapping, NamedNativeQuery and EntityResult for fetching single entity and multiple entities as List<Object[]>. In this application we rely on the {EntityName}.{RepositoryMethodName} naming convention. This convention allows us to create in the repository interface methods with the same name as of native named query.

Key points:


  1. How To Use JPA Named Queries @NamedQuery And Spring Projection (DTO)

Description: This application is an example of combining JPA named queries @NamedQuery and Spring projections (DTO). For queries names we use the {EntityName}.{RepositoryMethodName} naming convention. This convention allows us to create in the repository interface methods with the same name as of named query.

Key points:


  1. How To Use JPA Named Native Queries @NamedNativeQuery And Spring Projection (DTO)

Description: This application is an example of combining JPA named native queries @NamedNativeQuery and Spring projections (DTO). For queries names we use the {EntityName}.{RepositoryMethodName} naming convention. This convention allows us to create in the repository interface methods with the same name as of named native query.

Key points:


  1. How To Use JPA Named Queries Via a Properties File

Description: JPA named (native) queries are commonly written via @NamedQuery and @NamedNativeQuery annotations in entity classes. Spring Data allows us to write our named (native) queries in a typical *.properties file inside the META-INF folder of your classpath. This way, we avoid modifying our entities. This application shows you how to do it.

Warning: Cannot use native queries with dynamic sorting (Sort). Nevertheless, using Sort in named queries works fine. Moreover, using Sort in Pageable works fine for both, named queries and named native queries. At least this is how it behave in Spring Boot 2.2.2. From this point of view, this approach is better than using @NamedQuery/@NamedNativeQuery or orm.xml file.

Key points:


  1. How To Use JPA Named Queries Via The orm.xml File

Description: JPA named (native) queries are commonly written via @NamedQuery and @NamedNativeQuery annotations in entity classes. Spring Data allows us to write our named (native) queries in a typical orm.xml file inside the META-INF folder of your classpath. This way, we avoid modifying our entities. This application shows you how to do it.

Warning: Pay attention that, via this approach, we cannot use named (native) queries with dynamic sorting (Sort). Using Sort in Pageable is ignored, therefore you need to explicitly add ORDER BY in the queries. At least this is how it behave in Spring Boot 2.2.2. A better approach relies on using a properties file for listing the named (native) queries. In this case, dynamic Sort works for named queries, but not for named native queries. Using Sort in Pageable works as expected in named (native) queries.

Key points:


  1. How To Use JPA Named Queries Via Annotations

Description: JPA named (native) queries are commonly written via @NamedQuery and @NamedNativeQuery annotations in entity classes. This application shows you how to do it.

Warning: Pay attention that, via this approach, we cannot use named (native) queries with dynamic sorting (Sort). Using Sort in Pageable is ignored, therefore you need to explicitly add ORDER BY in the queries. At least this is how it behave in Spring Boot 2.2.2. A better approach relies on using a properties file for listing the named (native) queries. In this case, dynamic Sort works for named queries, but not for named native queries. Using Sort in Pageable works as expected in named (native) queries. And, you don’t need to modify/pollute entitites with the above annotations.

Key points:


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. How To Use JPA Named Queries Via Properties File And Spring Projection (DTO)

Description: This application is an example of combining JPA named queries listed in a properties file and Spring projections (DTO). For queries names we use the {EntityName}.{RepositoryMethodName} naming convention. This convention allows us to create in the repository interface methods with the same name as of named query.

Key points:


  1. How To Use JPA Named Native Queries Via Properties File And Spring Projection (DTO)

Description: This application is an example of combining JPA named native queries listed in a properties file and Spring projections (DTO). For queries names we use the {EntityName}.{RepositoryMethodName} naming convention. This convention allows us to create in the repository interface methods with the same name as of named native query.

Key points:


  1. How To Use JPA Named Queries Via orm.xml File And Spring Projection (DTO)

Description: This application is an example of combining JPA named queries listed in orm.xml file and Spring projections (DTO). For queries names we use the {EntityName}.{RepositoryMethodName} naming convention. This convention allows us to create in the repository interface methods with the same name as of named query.

Key points:


  1. How To Use JPA Named Native Queries Via orm.xml File And Spring Projection (DTO)

Description: This application is an example of combining JPA named native queries listed in orm.xml file and Spring projections (DTO). For queries names we use the {EntityName}.{RepositoryMethodName} naming convention. This convention allows us to create in the repository interface methods with the same name as of named native query.

Key points:


  1. How To Dto Via Named Native Query And Result Set Mapping Via orm.xml

Description: Fetching more data than needed is prone to performance penalities. Using DTO allows us to extract only the needed data. In this application we rely on named native queries and result set mapping via orm.xml and the {EntityName}.{RepositoryMethodName} naming convention. This convention allows us to create in the repository interface methods with the same name as of native named query.

Key points:


  1. How To Use Spring Projections(DTO) And Cross Joins

Description: This application is a proof of concept for using Spring Projections(DTO) and cross joins written via JPQL and native SQL (for MySQL).

Key points:


  1. Calling Stored Procedure That Returns A Result Set Via JdbcTemplate And BeanPropertyRowMapper

Description: This application is an example of calling a MySQL stored procedure that returns a result set via JdbcTemplate and BeanPropertyRowMapper.

Key points:


  1. Defining Entity Listener Class Via @EntityListeners

Description: This application is a sample of using the JPA @MappedSuperclass and @EntityListeners with JPA callbacks.

Key points:


  1. Improper Usage Of @Fetch(FetchMode.JOIN) May Causes N+1 Issues

Advice: Always evaluate JOIN FETCH and entities graphs before deciding to use FetchMode.JOIN. The FetchMode.JOIN fetch mode always triggers an EAGER load so the children are loaded when the parents are. Beside this drawback, FetchMode.JOIN may return duplicate results. You’ll have to remove the duplicates yourself (e.g. storing the result in a Set). But, if you decide to go with FetchMode.JOIN at least pay attention to avoid N+1 issues discussed below.

Note: Let’s assume three entities, Author, Book and Publisher. Between Author and Book there is a bidirectional-lazy @OneToMany association. Between Author and Publisher there is a unidirectional-lazy @ManyToOne. Between Book and Publisher there is no association.

Now, we want to fetch a book by id (BookRepository#findById()), including its author, and the author’s publisher. In such cases, using Hibernate fetch mode, @Fetch(FetchMode.JOIN) works as expected. Using JOIN FETCH or entity graph is also working as expected.

Next, we want to fetch all books (BookRepository#findAll()), including their authors, and the authors publishers. In such cases, using Hibernate fetch mode, @Fetch(FetchMode.JOIN) will cause N+1 issues. It will not trigger the expected JOIN. In this case, using JOIN FETCH or entity graph should be used.

Key points:


  1. How To Efficiently Assign A Database Temporary Ranking Of Values To Rows via RANK()

Description: This application is an example of assigning a database temporary ranking of values to rows via the window function, RANK(). This window function is available in almost all databases, and starting with version 8.x is available in MySQL as well.

Key points:

Output sample:


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. How To Efficiently Assign A Database Temporary Ranking Of Values To Rows via DENSE_RANK()

Description: This application is an example of assigning a database temporary ranking of values to rows via the window function, DENSE_RANK(). In comparison with the RANK() window function, DENSE_RANK() avoid gaps within partition. This window function is available in almost all databases, and starting with version 8.x is available in MySQL as well.

Key points:

Output sample:


  1. How To Efficiently Distribute The Number Of Rows In The Specified (N) Number Of Groups Via NTILE(N)

Description: This application is an example of distributing the number of rows in the specified (N) number of groups via the window function, NTILE(N). This window function is available in almost all databases, and starting with version 8.x is available in MySQL as well.

Key points:

Output sample:


  1. How To Write Derived Count And Delete Queries

Description: Spring Data comes with the Query Builder mechanism for JPA that is capable to interpret a query method name (known as a derived query) and convert it into a SQL query in the proper dialect. This is possible as long as we respect the naming conventions of this mechanism. Beside the well-known query of type find..., Spring Data supports derived count queries and derived delete queries.

Key points:


  1. Working With Spring Data Property Expressions

Description: Property expressions can refer to a direct property of the managed entity. However, you can also define constraints by traversing nested properties. This application is a sample of traversing nested properties for fetching entities and DTOs.

Key points:


  1. The Best Way To Fetch Parent And Children In Different Queries

Note: Fetching read-only data should be done via DTO, not managed entities. But, there is no tragedy to fetch read-only entities in a context as follows:

Under these circumstances, let’s tackle a common case that I saw quite a lot. There is even an SO answer about it (don’t do this):

Description: Let’s assume that Author and Book are involved in a bidirectional-lazy @OneToMany association. Imagine an user that loads a certain Author (without the associated Book). The user may be interested or not in the Book, therefore, we don’t load them with the Author. If the user is interested in the Book then he will click a button of type, View books. Now, we have to return the List<Book> associated to this Author.

So, at first request (query), we fetch an Author. The Author is detached. At second request (query), we want to load the Book associated to this Author. But, we don’t want to load the Author again (for example, we don’t care about lost updates of Author), we just want to load the associated Book in a single SELECT. A common (not recommended) approach is to load the Author again (e.g., via findById(author.getId())) and call the author.getBooks(). But, this end up in two SELECT statements. One SELECT for loading the Author, and another SELECT after we force the collection initialization. We force collection initialization because it will not be initialize if we simply return it. In order to trigger the collection initialization the developer call books.size() or he rely on Hibernate.initialize(books);.

But, we can avoid such solution by relying on an explicit JPQL or Query Builder property expressions. This way, there will be a single SELECT and no need to call size() or Hibernate.initialize();

Key points:

This item is detailed in my book, Spring Boot Persistence Best Practices.


  1. How To Optimize The Merge Operation Using Update

Description: Behind the built-in Spring Data save() there is a call of EntityManager#persist() or EntityManager#merge(). It is important to know this aspect in several cases. Among this cases, we have the entity update case (simple update or update batching).

Consider Author and Book involved in a bidirectional-lazy @OneToMany association. And, we load an Author, detach it, update it in the detached state, and save it to the database via save() method. Calling save() will come with the following two issues resulting from calling merge() behind the scene:

How about triggering only the UPDATE instead of this? The solution relies on calling Session#update(). Calling Session.update() requires to unwrap the Session via entityManager.unwrap(Session.class).

Key points:


  1. How To NOT Use Spring Data Streamable

Description: This application is a sample of fetching Streamable<entity> and Streamable<dto>. But, more important, this application contains three examples of how to not use Streamable. It is very tempting and comfortable to fetch a Streamable result set and chop it via filter(), map(), flatMap(), and so on until we obtain only the needed data instead of writing a query (e.g., JPQL) that fetches exactly the needed result set from the database. Mainly, we just throw away some of the fetched data to keep only the needed data. But, is not advisable to follow such practices because fetching more data than needed can cause significant performance penalties.

Moreover, pay attention to combining two or more Streamable via the and() method. The returned result may be different from what you are expecting to see. Each Streamable produces a separate SQL statement and the final result set is a concatenation of the intermediate results sets (prone to duplicate values).

Key points:


  1. How To Return Custom Streamable Wrapper Types

Description: A common practice consists of exposing dedicated wrappers types for collections resulted after mapping a query result set. This way, on a single query execution, the API can return multiple results. After we call a query-method that return a collection, we can pass it to a wrapper class by manually instantiation of that wrapper-class. But, we can avoid the manually instantiation if the code respects the following key points.

Key points:


  1. How To Use In Spring Boot JPA 2.1 Schema Generation And Data Loading

Description: JPA 2.1 come with schema generation features. This feature can setup the database or export the generated commands to a file. The parameters that we should set are:

Moreover, we can instruct the persistence provider to load data from a file into the database via: spring.jpa.properties.javax.persistence.sql-load-script-source. The value of this property represents the file location and it can be a file URL or a java.IO.Writer.

Key points:


  1. How To Return A Map Result From A Spring Data Query Method

Description: Sometimes, we need to write in repositories certain query-methods that return a Map instead of a List or a Set. For example, when we need a Map<Id, Entity> or we use GROUP BY and we need a Map<Group, Count>. This application shows you how to do it via default methods directly in repository.

Key points:


  1. How To Handle Entities Inheritance With Spring Data Repositories

Description: Consider one of the JPA inheritance strategies (e.g., JOINED). Handling entities inheritance With Spring Data repositories can be done as follows:


  1. Log Slow Queries Via Hibernate 5.4.5

Description: This application is a sample of logging only slow queries via Hibernate 5.4.5, hibernate.session.events.log.LOG_QUERIES_SLOWER_THAN_MS property. A slow query is a query that has an execution time bigger than a specificed threshold in milliseconds.

Key points:

Output example:


  1. DTO Via JDK14 Records And Spring Data Query Builder Mechanism

Description: Fetching more data than needed is prone to performance penalities. Using DTO allows us to extract only the needed data. In this application we rely on JDK14 Records feature and Spring Data Query Builder Mechanism.

From Openjdk JEP359:

Records provide a compact syntax for declaring classes which are transparent holders for shallowly immutable data.

Key points: Define the AuthorDto as:

public record AuthorDto(String name, int age) implements Serializable {}


  1. How To Fetch DTO Via JDK14 Records, Constructor Expression and JPQL

Description: Fetching more data than needed is prone to performance penalities. Using DTO allows us to extract only the needed data. In this application we rely on JDK 14 Records, Constructor Expression and JPQL.

From Openjdk JEP359:

Records provide a compact syntax for declaring classes which are transparent holders for shallowly immutable data.

Key points:

Define the AuthorDto as:

public record AuthorDto(String name, int age) implements Serializable {}


  1. How To Fetch DTO Via JDK14 Records And A Custom ResultTransformer

Description: Fetching more read-only data than needed is prone to performance penalties. Using DTO allows us to extract only the needed data. Sometimes, we need to fetch a DTO made of a subset of properties (columns) from a parent-child association. For such cases, we can use SQL JOIN that can pick up the desired columns from the involved tables. But, JOIN returns an List<Object[]> and most probably you will need to represent it as a List<ParentDto>, where a ParentDto instance has a List<ChildDto>. For such cases, we can rely on a custom Hibernate ResultTransformer. This application is a sample of writing a custom ResultTransformer.

As DTO, we rely on JDK 14 Records. From Openjdk JEP359:

Records provide a compact syntax for declaring classes which are transparent holders for shallowly immutable data.

Key points:


  1. DTO Via JDK14 Records, JdbcTemplate And ResultSetExtractor

Description: Fetching more data than needed is prone to performance penalities. Using DTO allows us to extract only the needed data. In this application we rely on JDK14 Records feature, JdbcTemplate and ResultSetExtractor.

From Openjdk JEP359:

Records provide a compact syntax for declaring classes which are transparent holders for shallowly immutable data.

Key points:


  1. Dynamic Spring projection (DTO class)

Description: This application is a sample of using dynamic Spring projections via DTO classes.

Key points:


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"If you need a hand of tips and illustrations of 100+ Java persistence performance issues then "Java Persistence Performance Illustrated Guide" is for you.


  1. Batch Inserts In Spring Boot Style Via CompletableFuture And Return List<S>

Description: This application is a sample of using CompletableFuture for batching inserts. This CompletableFuture uses an Executor that has the number of threads equal with the number of your computer cores. Usage is in Spring style. It returns List<S>:


  1. How to simulate a deadlock

Description: This application is an example of causing a database deadlock in MySQL. This application produces an exception of type: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction. However, the database will retry until transaction (A) succeeds.

Key points:


  1. How To Define A Composite Primary Key Having An Explicit Part and a Generated Part Via Sequence

Description: This application is a proof of concept of how to define a composite key having an explicit part (name) and a generated part (authorId via SEQUENCE generator).

Key points:


  1. How To Intercept The Generated SQL For Logging Or Altering

Description: Sometimes we need to intercept the generated SQL that originates from Spring Data, EntityManager, Criteria API, JdbcTemplate and so on. This can be done as in this sample application. After interception, you can log, modify or even return a brand new SQL that will be executed in the end.

Key points:


281.Force inline params in Criteria API

NOTE Use this with high precaution since you open the gate for SQL injections.

Description: Sometimes we need to force inline params in Criteria API. By default, numeric parameters are inlined, but string parameters are not.

Key points:


  1. Using Arthur Gavlyukovskiy’s data source decorator

Description: Arthur Gavlyukovskiy provide a suite of Spring Boot starters for quickly integrate P6Spy, Datasource Proxy, and FlexyPool. In this example, we add Datasource Proxy, but please consider this for more details.

Key points:


  1. Using Java records as Hibernate embeddable

Description: This application is an example of using Java records as embeddable. This is available starting with Hibernate 6.0, but it was refined to be more accessible and easy to use in Hibernate 6.2

Key points: