From c100674f327f1d576ed34c132c5e8f6b317d99fe Mon Sep 17 00:00:00 2001 From: Gavin Date: Mon, 15 May 2023 10:56:04 +0200 Subject: [PATCH] document query cache --- .../main/asciidoc/introduction/Entities.adoc | 7 +- .../main/asciidoc/introduction/Tuning.adoc | 69 ++++++++++++++++++- 2 files changed, 70 insertions(+), 6 deletions(-) diff --git a/documentation/src/main/asciidoc/introduction/Entities.adoc b/documentation/src/main/asciidoc/introduction/Entities.adoc index b6ab9411ac..74ef88c4d9 100644 --- a/documentation/src/main/asciidoc/introduction/Entities.adoc +++ b/documentation/src/main/asciidoc/introduction/Entities.adoc @@ -670,7 +670,7 @@ public static class EnumSetConverter implements AttributeConverter enumSet) { int encoded = 0; - DayOfWeek[] values = DayOfWeek.values(); + var values = DayOfWeek.values(); for (int i = 0; i convertToEntityAttribute(Integer encoded) { - EnumSet set = EnumSet.noneOf(DayOfWeek.class); - DayOfWeek[] values = DayOfWeek.values(); + var set = EnumSet.noneOf(DayOfWeek.class); + var values = DayOfWeek.values(); for (int i = 0; i books; + ... +} +---- + +The cache defined by a `@Cache` annotation is automatically utilized by Hibernate to: + +- retrieve an entity by id when `find()` is called, or +- to resolve an association by id. The `@Cache` annotation always specifies a `CacheConcurrencyStrategy`, a policy governing access to the second-level cache by concurrent transactions. @@ -288,7 +307,7 @@ Book book = s.byNaturalId().using("isbn", isbn, "printing", printing).load(); [NOTE] ==== -Since the natural id cache doesn't contain the actual state of the entity, it doesn't make sense to annotate an entity `@NaturalIdCache` unless it is already eligible for storage in the second-level cache, that is, unless it's also annotated `@Cache`. +Since the natural id cache doesn't contain the actual state of the entity, it doesn't make sense to annotate an entity `@NaturalIdCache` unless it's already eligible for storage in the second-level cache, that is, unless it's also annotated `@Cache`. ==== Once we've marked an entity or collection as eligible for storage in the second-level cache, we still need to set up an actual cache. @@ -315,6 +334,50 @@ your entities and collections. You can find much more information about the second-level cache in the {second-level-cache}[User Guide]. +[[query-cache]] +=== Caching query result sets + +The caches we've described above are only used to optimize lookups by id or by natural id. +Hibernate also has a way to cache the result sets of queries, though this is only rarely an efficient thing to do. + +To cache the results of a query, call `SelectionQuery.setCacheable(true)`: + +[source,java] +---- +s.createQuery("from Product where discontinued = false") + .setCacheable(true) + .getResultList(); +---- + +By default, the query result set is stored in a cache region named `default-query-results-region`. +Since different queries should have different caching policies, it's common to explicitly specify a region name: + +[source,java] +---- +s.createQuery("from Product where discontinued = false") + .setCacheable(true) + .setCacheRegion("ProductCatalog") + .getResultList(); +---- + +A result set is cached together with a _logical timestamp_. +By "logical", we mean that it doesn't actually increase linearly with time, and in particular it's not the system time. + +When a `Product` is updated, Hibernate _does not_ go through the query cache and invalidate every cached result set that's affected by the change. +Instead, there's a special region of the cache which holds a logical timestamp of the most-recent update to each table. +This is called the _update timestamps cache_, and it's kept in the region `default-update-timestamps-region`. + +[CAUTION] +==== +It's _your responsibility_ to ensure that this cache region is configured with appropriate policies. +In particular, update timestamps should never expire or be evicted. +==== + +When a query result set is read from the cache, Hibernate compares its timestamp with the timestamp of each of the tables that affect the results of the query, and _only_ returns the result set if the result set isn't stale. +If the result set _is_ stale, Hibernate goes ahead and re-executes the query against the database and updates the cached result set. + +As is generally the case with any second-level cache, the query cache can break the ACID properties of transactions. + [[second-level-cache-management]] === Second-level cache management