Skip to content

Commit 0557879

Browse files
committed
HHH-15086 Introduce configurable query cache layout
1 parent 1101568 commit 0557879

File tree

156 files changed

+6135
-2387
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

156 files changed

+6135
-2387
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.annotations;
8+
9+
import org.hibernate.Incubating;
10+
11+
/**
12+
* Describes the data layout used for storing an object into the query cache.
13+
* <p>
14+
* The query cache can either store the full state of an entity or collection,
15+
* or store only the identifier and discriminator if needed. Both approaches have pros and cons,
16+
* but ultimately it's advisable to us a shallow layout if the chances are high,
17+
* that the object will be contained in the second level cache.
18+
*
19+
* @see QueryCacheLayout
20+
* @since 6.5
21+
*/
22+
@Incubating
23+
public enum CacheLayout {
24+
/**
25+
* Uses either {@link #SHALLOW} or {@link #FULL},
26+
* depending on whether an entity or collection is second level cacheable.
27+
*/
28+
AUTO,
29+
30+
/**
31+
* Uses a cache layout that only stores the identifier of the entity or collection.
32+
* This is useful when the chances for the object being part of the second level cache are very high.
33+
*/
34+
SHALLOW,
35+
36+
/**
37+
* Like {@link #SHALLOW} but will also store the entity discriminator.
38+
*/
39+
SHALLOW_WITH_DISCRIMINATOR,
40+
41+
/**
42+
* Stores the full state into the query cache.
43+
* This is useful when the chances for the object being part of the second level cache are very low.
44+
*/
45+
FULL;
46+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.annotations;
8+
9+
import java.lang.annotation.Retention;
10+
import java.lang.annotation.Target;
11+
12+
import org.hibernate.Incubating;
13+
14+
import static java.lang.annotation.ElementType.FIELD;
15+
import static java.lang.annotation.ElementType.METHOD;
16+
import static java.lang.annotation.ElementType.TYPE;
17+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
18+
19+
/**
20+
* Configures the layout for the entity or collection data in a query cache.
21+
*
22+
* @see CacheLayout
23+
* @see jakarta.persistence.Cacheable
24+
* @see org.hibernate.Cache
25+
* @see org.hibernate.cfg.AvailableSettings#CACHE_REGION_FACTORY
26+
* @see org.hibernate.cfg.AvailableSettings#USE_SECOND_LEVEL_CACHE
27+
* @see org.hibernate.cfg.AvailableSettings#USE_QUERY_CACHE
28+
* @since 6.5
29+
*
30+
*/
31+
@Target({TYPE, FIELD, METHOD})
32+
@Retention(RUNTIME)
33+
@Incubating
34+
public @interface QueryCacheLayout {
35+
36+
/**
37+
* The layout of the data for an entity or collection in the query cache.
38+
*/
39+
CacheLayout layout() default CacheLayout.AUTO;
40+
}

hibernate-core/src/main/java/org/hibernate/boot/SessionFactoryBuilder.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.hibernate.Interceptor;
1515
import org.hibernate.SessionFactory;
1616
import org.hibernate.SessionFactoryObserver;
17+
import org.hibernate.annotations.CacheLayout;
1718
import org.hibernate.cache.spi.TimestampsCacheFactory;
1819
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
1920
import org.hibernate.jpa.spi.JpaCompliance;
@@ -445,6 +446,19 @@ public interface SessionFactoryBuilder {
445446
*/
446447
SessionFactoryBuilder applyQueryCacheSupport(boolean enabled);
447448

449+
/**
450+
* Specifies the default {@link CacheLayout} to use for query cache entries.
451+
*
452+
* @param cacheLayout The cache layout to use.
453+
*
454+
* @return {@code this}, for method chaining
455+
*
456+
* @see org.hibernate.cfg.AvailableSettings#QUERY_CACHE_LAYOUT
457+
* @since 6.5
458+
*/
459+
@Incubating
460+
SessionFactoryBuilder applyQueryCacheLayout(CacheLayout cacheLayout);
461+
448462
/**
449463
* Specifies a {@link org.hibernate.cache.spi.TimestampsCacheFactory}.
450464
*

hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryBuilderImpl.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.hibernate.Interceptor;
1515
import org.hibernate.SessionFactory;
1616
import org.hibernate.SessionFactoryObserver;
17+
import org.hibernate.annotations.CacheLayout;
1718
import org.hibernate.boot.SessionFactoryBuilder;
1819
import org.hibernate.boot.TempTableDdlTransactionHandling;
1920
import org.hibernate.boot.spi.BootstrapContext;
@@ -285,6 +286,12 @@ public SessionFactoryBuilder applyQueryCacheSupport(boolean enabled) {
285286
return this;
286287
}
287288

289+
@Override
290+
public SessionFactoryBuilder applyQueryCacheLayout(CacheLayout cacheLayout) {
291+
this.optionsBuilder.applyQueryCacheLayout( cacheLayout );
292+
return this;
293+
}
294+
288295
@Override
289296
public SessionFactoryBuilder applyTimestampsCacheFactory(TimestampsCacheFactory factory) {
290297
this.optionsBuilder.applyTimestampsCacheFactory( factory );

hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.util.Collections;
1313
import java.util.HashMap;
1414
import java.util.List;
15+
import java.util.Locale;
1516
import java.util.Map;
1617
import java.util.TimeZone;
1718
import java.util.concurrent.Callable;
@@ -24,6 +25,7 @@
2425
import org.hibernate.SessionEventListener;
2526
import org.hibernate.SessionFactoryObserver;
2627
import org.hibernate.TimeZoneStorageStrategy;
28+
import org.hibernate.annotations.CacheLayout;
2729
import org.hibernate.boot.SchemaAutoTooling;
2830
import org.hibernate.boot.TempTableDdlTransactionHandling;
2931
import org.hibernate.boot.registry.StandardServiceRegistry;
@@ -126,6 +128,7 @@
126128
import static org.hibernate.cfg.AvailableSettings.USE_SQL_COMMENTS;
127129
import static org.hibernate.cfg.AvailableSettings.USE_STRUCTURED_CACHE;
128130
import static org.hibernate.cfg.AvailableSettings.USE_SUBSELECT_FETCH;
131+
import static org.hibernate.cfg.CacheSettings.QUERY_CACHE_LAYOUT;
129132
import static org.hibernate.engine.config.spi.StandardConverters.BOOLEAN;
130133
import static org.hibernate.internal.CoreLogging.messageLogger;
131134
import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER;
@@ -228,6 +231,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
228231
// Caching
229232
private boolean secondLevelCacheEnabled;
230233
private boolean queryCacheEnabled;
234+
private CacheLayout queryCacheLayout;
231235
private TimestampsCacheFactory timestampsCacheFactory;
232236
private String cacheRegionPrefix;
233237
private boolean minimalPutsEnabled;
@@ -442,6 +446,11 @@ public SessionFactoryOptionsBuilder(StandardServiceRegistry serviceRegistry, Boo
442446
if ( !(regionFactory instanceof NoCachingRegionFactory) ) {
443447
this.secondLevelCacheEnabled = configurationService.getSetting( USE_SECOND_LEVEL_CACHE, BOOLEAN, true );
444448
this.queryCacheEnabled = configurationService.getSetting( USE_QUERY_CACHE, BOOLEAN, false );
449+
this.queryCacheLayout = configurationService.getSetting(
450+
QUERY_CACHE_LAYOUT,
451+
value -> CacheLayout.valueOf( value.toString().toUpperCase( Locale.ROOT ) ),
452+
CacheLayout.FULL
453+
);
445454
this.timestampsCacheFactory = strategySelector.resolveDefaultableStrategy(
446455
TimestampsCacheFactory.class,
447456
configurationSettings.get( QUERY_CACHE_FACTORY ),
@@ -467,6 +476,7 @@ public SessionFactoryOptionsBuilder(StandardServiceRegistry serviceRegistry, Boo
467476
else {
468477
this.secondLevelCacheEnabled = false;
469478
this.queryCacheEnabled = false;
479+
this.queryCacheLayout = CacheLayout.AUTO;
470480
this.timestampsCacheFactory = null;
471481
this.cacheRegionPrefix = null;
472482
this.minimalPutsEnabled = false;
@@ -1048,6 +1058,11 @@ public boolean isQueryCacheEnabled() {
10481058
return queryCacheEnabled;
10491059
}
10501060

1061+
@Override
1062+
public CacheLayout getQueryCacheLayout() {
1063+
return queryCacheLayout;
1064+
}
1065+
10511066
@Override
10521067
public TimestampsCacheFactory getTimestampsCacheFactory() {
10531068
return timestampsCacheFactory;
@@ -1428,6 +1443,10 @@ public void enableQueryCacheSupport(boolean enabled) {
14281443
this.queryCacheEnabled = enabled;
14291444
}
14301445

1446+
public void applyQueryCacheLayout(CacheLayout queryCacheLayout) {
1447+
this.queryCacheLayout = queryCacheLayout;
1448+
}
1449+
14311450
public void applyTimestampsCacheFactory(TimestampsCacheFactory factory) {
14321451
this.timestampsCacheFactory = factory;
14331452
}

hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.hibernate.annotations.Bag;
2323
import org.hibernate.annotations.BatchSize;
2424
import org.hibernate.annotations.Cache;
25+
import org.hibernate.annotations.CacheLayout;
2526
import org.hibernate.annotations.Cascade;
2627
import org.hibernate.annotations.Check;
2728
import org.hibernate.annotations.Checks;
@@ -63,6 +64,7 @@
6364
import org.hibernate.annotations.OptimisticLock;
6465
import org.hibernate.annotations.Parameter;
6566
import org.hibernate.annotations.Persister;
67+
import org.hibernate.annotations.QueryCacheLayout;
6668
import org.hibernate.annotations.SQLDelete;
6769
import org.hibernate.annotations.SQLDeleteAll;
6870
import org.hibernate.annotations.SQLInsert;
@@ -214,6 +216,7 @@ public abstract class CollectionBinder {
214216
private String cascadeStrategy;
215217
private String cacheConcurrencyStrategy;
216218
private String cacheRegionName;
219+
private CacheLayout queryCacheLayout;
217220
private boolean oneToMany;
218221
protected IndexColumn indexColumn;
219222
protected OnDeleteAction onDeleteAction;
@@ -288,6 +291,7 @@ public static void bindCollection(
288291
collectionBinder.setNaturalSort( property.getAnnotation( SortNatural.class ) );
289292
collectionBinder.setComparatorSort( property.getAnnotation( SortComparator.class ) );
290293
collectionBinder.setCache( property.getAnnotation( Cache.class ) );
294+
collectionBinder.setQueryCacheLayout( property.getAnnotation( QueryCacheLayout.class ) );
291295
collectionBinder.setPropertyHolder(propertyHolder);
292296

293297
collectionBinder.setNotFoundAction( notFoundAction( propertyHolder, inferredData, property, manyToManyAnn ) );
@@ -1251,6 +1255,7 @@ private void bindCache() {
12511255
collection.setCacheConcurrencyStrategy( cacheConcurrencyStrategy );
12521256
collection.setCacheRegionName( cacheRegionName );
12531257
}
1258+
collection.setQueryCacheLayout( queryCacheLayout );
12541259
}
12551260

12561261
private void bindExplicitTypes() {
@@ -1938,6 +1943,10 @@ public void setCache(Cache cache) {
19381943
}
19391944
}
19401945

1946+
public void setQueryCacheLayout(QueryCacheLayout queryCacheLayout) {
1947+
this.queryCacheLayout = queryCacheLayout == null ? null : queryCacheLayout.layout();
1948+
}
1949+
19411950
public void setOneToMany(boolean oneToMany) {
19421951
this.oneToMany = oneToMany;
19431952
}

hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.hibernate.annotations.BatchSize;
2424
import org.hibernate.annotations.Cache;
2525
import org.hibernate.annotations.CacheConcurrencyStrategy;
26+
import org.hibernate.annotations.CacheLayout;
2627
import org.hibernate.annotations.Check;
2728
import org.hibernate.annotations.Checks;
2829
import org.hibernate.annotations.DiscriminatorFormula;
@@ -43,6 +44,7 @@
4344
import org.hibernate.annotations.Polymorphism;
4445
import org.hibernate.annotations.PolymorphismType;
4546
import org.hibernate.annotations.Proxy;
47+
import org.hibernate.annotations.QueryCacheLayout;
4648
import org.hibernate.annotations.RowId;
4749
import org.hibernate.annotations.SQLDelete;
4850
import org.hibernate.annotations.SQLDeleteAll;
@@ -201,6 +203,7 @@ public class EntityBinder {
201203
private String cacheRegion;
202204
private boolean cacheLazyProperty;
203205
private String naturalIdCacheRegion;
206+
private CacheLayout queryCacheLayout;
204207

205208
/**
206209
* Bind an entity class. This can be done in a single pass.
@@ -1271,6 +1274,7 @@ public void bindEntity() {
12711274
persistentClass.setEntityName( annotatedClass.getName() );
12721275
persistentClass.setCached( isCached );
12731276
persistentClass.setLazy( lazy );
1277+
persistentClass.setQueryCacheLayout( queryCacheLayout );
12741278
if ( proxyClass != null ) {
12751279
persistentClass.setProxyInterfaceName( proxyClass.getName() );
12761280
}
@@ -1599,6 +1603,7 @@ private void bindCache() {
15991603
cacheConcurrentStrategy = null;
16001604
cacheRegion = null;
16011605
cacheLazyProperty = true;
1606+
queryCacheLayout = null;
16021607
final SharedCacheMode sharedCacheMode = context.getBuildingOptions().getSharedCacheMode();
16031608
if ( persistentClass instanceof RootClass ) {
16041609
bindRootClassCache( sharedCacheMode, context );
@@ -1643,6 +1648,9 @@ private void bindRootClassCache(SharedCacheMode sharedCacheMode, MetadataBuildin
16431648
cacheConcurrentStrategy = resolveCacheConcurrencyStrategy( effectiveCache.usage() );
16441649
cacheRegion = effectiveCache.region();
16451650
cacheLazyProperty = isCacheLazy( effectiveCache, annotatedClass );
1651+
1652+
final QueryCacheLayout queryCache = annotatedClass.getAnnotation( QueryCacheLayout.class );
1653+
queryCacheLayout = queryCache == null ? null : queryCache.layout();
16461654
}
16471655

16481656
private static boolean isCacheLazy(Cache effectiveCache, XClass annotatedClass) {

hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryBuilder.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.hibernate.Interceptor;
1414
import org.hibernate.SessionFactory;
1515
import org.hibernate.SessionFactoryObserver;
16+
import org.hibernate.annotations.CacheLayout;
1617
import org.hibernate.boot.SessionFactoryBuilder;
1718
import org.hibernate.boot.TempTableDdlTransactionHandling;
1819
import org.hibernate.cache.spi.TimestampsCacheFactory;
@@ -245,6 +246,12 @@ public T applyQueryCacheSupport(boolean enabled) {
245246
return getThis();
246247
}
247248

249+
@Override
250+
public SessionFactoryBuilder applyQueryCacheLayout(CacheLayout cacheLayout) {
251+
delegate.applyQueryCacheLayout( cacheLayout );
252+
return getThis();
253+
}
254+
248255
@Override
249256
public SessionFactoryBuilder applyTimestampsCacheFactory(TimestampsCacheFactory factory) {
250257
delegate.applyTimestampsCacheFactory( factory );

hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.hibernate.Interceptor;
1616
import org.hibernate.SessionFactoryObserver;
1717
import org.hibernate.TimeZoneStorageStrategy;
18+
import org.hibernate.annotations.CacheLayout;
1819
import org.hibernate.boot.SchemaAutoTooling;
1920
import org.hibernate.boot.TempTableDdlTransactionHandling;
2021
import org.hibernate.boot.registry.StandardServiceRegistry;
@@ -253,6 +254,11 @@ public boolean isQueryCacheEnabled() {
253254
return delegate.isQueryCacheEnabled();
254255
}
255256

257+
@Override
258+
public CacheLayout getQueryCacheLayout() {
259+
return delegate.getQueryCacheLayout();
260+
}
261+
256262
@Override
257263
public TimestampsCacheFactory getTimestampsCacheFactory() {
258264
return delegate.getTimestampsCacheFactory();

hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.hibernate.Interceptor;
1616
import org.hibernate.SessionFactoryObserver;
1717
import org.hibernate.TimeZoneStorageStrategy;
18+
import org.hibernate.annotations.CacheLayout;
1819
import org.hibernate.boot.SchemaAutoTooling;
1920
import org.hibernate.boot.TempTableDdlTransactionHandling;
2021
import org.hibernate.boot.registry.StandardServiceRegistry;
@@ -166,6 +167,9 @@ default boolean isAllowRefreshDetachedEntity() {
166167

167168
boolean isQueryCacheEnabled();
168169

170+
@Incubating
171+
CacheLayout getQueryCacheLayout();
172+
169173
TimestampsCacheFactory getTimestampsCacheFactory();
170174

171175
String getCacheRegionPrefix();

0 commit comments

Comments
 (0)