| |

11 JPA and Hibernate query hints every developer should know


Take your skills to the next level!

The Persistence Hub is the place to be for every Java developer. It gives you access to all my premium video courses, monthly Java Persistence News, monthly coding problems, and regular expert sessions.


JPA and Hibernate support a set of hints that you can use to provide additional information to your persistence provider to influence the execution of a query. You can use them for lots of different things, like setting a timeout for your query, using an entity graph, or defining the caching of a query result.

When you use a query hint, please keep in mind that Hibernate doesn’t have to use it. Like a recommendation or hint you give another human, Hibernate can ignore it. This is usually only the case if the implementation of the hint relies on a specific feature provided by some JDBC drivers.

How to use query hints

But before we start with the list of hints, let’s have a quick look at how you can use a query hint. You can provide it to the EntityManager.find method, the Query interface for named and ad-hoc queries, or the definition of a @NamedQuery. The only sad thing about this is that the syntax for each of them is a little bit different.

The EntityManager.find method accepts a HashMap<String, Object> as an additional parameter to provide the hints.

EntityGraph<?> graph = em.getEntityGraph("graph.AuthorBooks");

HashMap<String, Object> properties = new HashMap<>();
properties.put("javax.persistence.fetchgraph", graph);

em.find(Author.class, 1L, properties);

The Query interface provides the setHint(String name, Object value) method, which you have to call for each hint you want to provide.

EntityGraph<?> graph = em.getEntityGraph("graph.AuthorBooks");

em.createQuery("SELECT a FROM Author a")
  .setHint("javax.persistence.fetchgraph", graph)
  .getResultList();

And you can also provide hints to the @NamedQuery annotation to add them to the definition of the named query.

@NamedQuery(name = "selectAuthors", query = "SELECT a FROM Author a", 
            hints = @QueryHint(name = QueryHints.COMMENT, value = "a custom SQL comment"))

In this case, the hints will be used for each instantiation of this named query, and you don’t have to set them on the Query interface.

em.createNamedQuery("selectAuthors").getResultList();

JPA Hints

Let’s start with the hints defined by the JPA specification. Their names depend on your JPA version. For JPA 1 and 2, their names start with javax.persistence. Starting with JPA 3, the names start with jakarta.persistence.

1. jakarta.persistence.lock.timeout (Long – milliseconds)

(Previously: javax.persistence.lock.timeout)

This hint defines the timeout in milliseconds to acquire a pessimistic lock.

2. jakarta.persistence.query.timeout (Long – milliseconds)

(Previously: javax.persistence.query.timeout)

The jakarta.persistence.query.timeout hint defines how long a query is allowed to run before it gets canceled. Hibernate doesn’t handle this timeout itself but provides it to the JDBC driver via the JDBC Statement.setTimeout method.

3. jakarta.persistence.cache.retrieveMode (CacheRetrieveMode – USE | BYPASS)

(Previously: javax.persistence.cache.retrieveMode)

The retrieveMode hint supports the values USE and BYPASS and tells Hibernate if it shall USE the second-level cache to retrieve an entity or if it shall BYPASS it and get it directly from the database.

4. jakarta.persistence.cache.storeMode (CacheStoreMode – USE | BYPASS | REFRESH)

(Previously: javax.persistence.cache.storeMode)

This hint defines how Hibernate shall write changed entities to the second-level cache. It can either USE the cache to add entities to the cache and update existing ones, or BYPASS it for entities that are not already stored in the cache and only update the existing ones, or REFRESH the entities located in the cache before they get retrieved from it.

5. jakarta.persistence.loadgraph (EntityGraph)

(Previously: javax.persistence.loadgraph)

The jakarta.persistence.loadgraph hint allows you to provide an entity graph as a load graph to the query to define eager fetching specifically for this query.

You can read more about entity graphs in JPA Entity Graph – Part 1: Named entity graphs and JPA Entity Graph – Part 2: Define lazy/eager loading at runtime.

6. jakarta.persistence.fetchgraph (EntityGraph)

(Previously: javax.persistence.fetchgraph)

You can use this hint to provide an entity graph as a fetchgraph to a query.

You can read more about entity graphs in JPA Entity Graph – Part 1: Named entity graphs and JPA Entity Graph – Part 2: Define lazy/eager loading at runtime.

Hibernate Hints

These were the most important query hints defined by the JPA specification. Let’s continue with the Hibernate-specific ones.

7. org.hibernate.flushMode (FlushMode – AUTO | ALWAYS | COMMIT | MANUAL)

If you modify an entity, Hibernate keeps these changes in the first-level cache until it gets flushed. When and how Hibernate performs a flush operation depends on your configured FlushMode.

One way to define the FlushMode is by providing a value of the org.hibernate.FlushMode enum as the org.hibernate.flushMode hint. You can choose between:

  • AUTO = Hibernate decides if the changes have to be written to the database,
  • ALWAYS = The Session gets flushed before every query,
  • COMMIT = Hibernate will not write any changes to the database until the transaction gets committed,
  • MANUAL = You have to flush the Session yourself.

8. org.hibernate.readOnly (boolean)

If you do not apply any changes to the selected entities, you can set the org.hibernate.readOnly hint to true. This allows Hibernate to deactivate dirty checking for these entities, which can provide a performance benefit.

You can learn more about the performance benefits and pitfalls of read-only queries in this article or the Hibernate Performance Tuning course included in the Persistence Hub.

9. org.hibernate.fetchSize (Long – number of records)

Hibernate provides the value of this hint to the JDBC driver to define the number of rows the driver shall receive in one batch. This can improve the communication between the JDBC driver and the database if it’s supported by the driver.

10. org.hibernate.comment (String – custom comment)

If you set the hibernate.use_sql_comments property in your persistence.xml file to true, Hibernate generates a comment for each query and writes it to the log file. This can be useful if you have to analyze huge or complex SQL logs.

You can use the org.hibernate.comment hint to provide your own comment for a query.

11. org.hibernate.cacheable

If you want to use Hibernate’s query cache, you have to activate it in the persistence.xml file and enable it for a specific query by setting the org.hibernate.cacheable hint to true.

Summary

As you have seen, JPA and Hibernate provide a set of hints that you can use to customize and optimize the execution of a query. Especially the ones related to caching and entity graphs can provide huge performance benefits to your application.

7 Comments

  1. org.hibernate.cachable: if every develop should know it then they should know it’s actually org.hibernate.cacheable

    1. Avatar photo Thorben Janssen says:

      Ooops, thanks for pointing out.
      Typo fixed

      1. ty. Now I can C/P from here again 🙂

        1. Avatar photo Thorben Janssen says:

          Awesome 🙂

  2. Thank you very much for this interesting article !

    1. Avatar photo Thorben Janssen says:

      You’re welcome!
      I’m glad you like it.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.