HHH-12146 - Support enabling caching at any level within a mapped hierarchy
This commit is contained in:
parent
6edff69101
commit
59c3baae32
|
@ -61,7 +61,7 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
|
|||
for ( Queryable persister : affectedQueryables ) {
|
||||
spacesList.addAll( Arrays.asList( (String[]) persister.getQuerySpaces() ) );
|
||||
|
||||
if ( persister.hasCache() ) {
|
||||
if ( persister.canWriteToCache() ) {
|
||||
entityCleanups.add( new EntityCleanup( persister.getCacheAccessStrategy() ) );
|
||||
}
|
||||
if ( persister.hasNaturalIdentifier() && persister.hasNaturalIdCache() ) {
|
||||
|
@ -105,7 +105,7 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
|
|||
if ( affectedEntity( tableSpaces, entitySpaces ) ) {
|
||||
spacesList.addAll( Arrays.asList( entitySpaces ) );
|
||||
|
||||
if ( persister.hasCache() ) {
|
||||
if ( persister.canWriteToCache() ) {
|
||||
entityCleanups.add( new EntityCleanup( persister.getCacheAccessStrategy() ) );
|
||||
}
|
||||
if ( persister.hasNaturalIdentifier() && persister.hasNaturalIdCache() ) {
|
||||
|
|
|
@ -78,7 +78,7 @@ public abstract class EntityAction
|
|||
protected abstract boolean hasPostCommitEventListeners();
|
||||
|
||||
protected boolean needsAfterTransactionCompletion() {
|
||||
return persister.hasCache() || hasPostCommitEventListeners();
|
||||
return persister.canWriteToCache() || hasPostCommitEventListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -86,7 +86,7 @@ public class EntityDeleteAction extends EntityAction {
|
|||
}
|
||||
|
||||
final Object ck;
|
||||
if ( persister.hasCache() ) {
|
||||
if ( persister.canWriteToCache() ) {
|
||||
final EntityRegionAccessStrategy cache = persister.getCacheAccessStrategy();
|
||||
ck = cache.generateCacheKey( id, persister, session.getFactory(), session.getTenantIdentifier() );
|
||||
lock = cache.lockItem( session, ck, version );
|
||||
|
@ -113,7 +113,7 @@ public class EntityDeleteAction extends EntityAction {
|
|||
persistenceContext.removeEntity( entry.getEntityKey() );
|
||||
persistenceContext.removeProxy( entry.getEntityKey() );
|
||||
|
||||
if ( persister.hasCache() ) {
|
||||
if ( persister.canWriteToCache() ) {
|
||||
persister.getCacheAccessStrategy().remove( session, ck);
|
||||
}
|
||||
|
||||
|
@ -187,7 +187,7 @@ public class EntityDeleteAction extends EntityAction {
|
|||
@Override
|
||||
public void doAfterTransactionCompletion(boolean success, SharedSessionContractImplementor session) throws HibernateException {
|
||||
EntityPersister entityPersister = getPersister();
|
||||
if ( entityPersister.hasCache() ) {
|
||||
if ( entityPersister.canWriteToCache() ) {
|
||||
EntityRegionAccessStrategy cache = entityPersister.getCacheAccessStrategy();
|
||||
final Object ck = cache.generateCacheKey(
|
||||
getId(),
|
||||
|
|
|
@ -249,7 +249,7 @@ public final class EntityInsertAction extends AbstractEntityInsertAction {
|
|||
}
|
||||
|
||||
private boolean isCachePutEnabled(EntityPersister persister, SharedSessionContractImplementor session) {
|
||||
return persister.hasCache()
|
||||
return persister.canWriteToCache()
|
||||
&& !persister.isCacheInvalidationRequired()
|
||||
&& session.getCacheMode().isPutEnabled();
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@ public final class EntityUpdateAction extends EntityAction {
|
|||
}
|
||||
|
||||
final Object ck;
|
||||
if ( persister.hasCache() ) {
|
||||
if ( persister.canWriteToCache() ) {
|
||||
final EntityRegionAccessStrategy cache = persister.getCacheAccessStrategy();
|
||||
ck = cache.generateCacheKey(
|
||||
id,
|
||||
|
@ -184,7 +184,7 @@ public final class EntityUpdateAction extends EntityAction {
|
|||
entry.postUpdate( instance, state, nextVersion );
|
||||
}
|
||||
|
||||
if ( persister.hasCache() ) {
|
||||
if ( persister.canWriteToCache() ) {
|
||||
if ( persister.isCacheInvalidationRequired() || entry.getStatus()!= Status.MANAGED ) {
|
||||
persister.getCacheAccessStrategy().remove( session, ck);
|
||||
}
|
||||
|
@ -310,7 +310,7 @@ public final class EntityUpdateAction extends EntityAction {
|
|||
@Override
|
||||
public void doAfterTransactionCompletion(boolean success, SharedSessionContractImplementor session) throws CacheException {
|
||||
final EntityPersister persister = getPersister();
|
||||
if ( persister.hasCache() ) {
|
||||
if ( persister.canWriteToCache() ) {
|
||||
final EntityRegionAccessStrategy cache = persister.getCacheAccessStrategy();
|
||||
final Object ck = cache.generateCacheKey(
|
||||
getId(),
|
||||
|
|
|
@ -2146,6 +2146,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
|
|||
"Cache override referenced a non-root entity : " + cacheRegionDefinition.getRole()
|
||||
);
|
||||
}
|
||||
entityBinding.setCached( true );
|
||||
( (RootClass) entityBinding ).setCacheRegionName( cacheRegionDefinition.getRegion() );
|
||||
( (RootClass) entityBinding ).setCacheConcurrencyStrategy( cacheRegionDefinition.getUsage() );
|
||||
( (RootClass) entityBinding ).setLazyPropertiesCacheable( cacheRegionDefinition.isCacheLazy() );
|
||||
|
|
|
@ -331,7 +331,7 @@ public class ModelBinder {
|
|||
}
|
||||
rootEntityDescriptor.setCacheRegionName( caching.getRegion() );
|
||||
rootEntityDescriptor.setLazyPropertiesCacheable( caching.isCacheLazyProperties() );
|
||||
rootEntityDescriptor.setCachingExplicitlyRequested( caching.getRequested() != TruthValue.UNKNOWN );
|
||||
rootEntityDescriptor.setCached( caching.getRequested() != TruthValue.UNKNOWN );
|
||||
}
|
||||
|
||||
private void bindEntityIdentifier(
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.cfg;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
@ -21,7 +20,6 @@ import java.util.Map;
|
|||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Cacheable;
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ConstraintMode;
|
||||
|
@ -78,7 +76,6 @@ import org.hibernate.FetchMode;
|
|||
import org.hibernate.MappingException;
|
||||
import org.hibernate.annotations.BatchSize;
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.annotations.Cascade;
|
||||
import org.hibernate.annotations.CascadeType;
|
||||
import org.hibernate.annotations.Check;
|
||||
|
@ -105,7 +102,6 @@ import org.hibernate.annotations.ListIndexBase;
|
|||
import org.hibernate.annotations.ManyToAny;
|
||||
import org.hibernate.annotations.MapKeyType;
|
||||
import org.hibernate.annotations.NaturalId;
|
||||
import org.hibernate.annotations.NaturalIdCache;
|
||||
import org.hibernate.annotations.NotFound;
|
||||
import org.hibernate.annotations.NotFoundAction;
|
||||
import org.hibernate.annotations.OnDelete;
|
||||
|
@ -625,8 +621,7 @@ public final class AnnotationBinder {
|
|||
entityBinder.setProxy( clazzToProcess.getAnnotation( Proxy.class ) );
|
||||
entityBinder.setBatchSize( clazzToProcess.getAnnotation( BatchSize.class ) );
|
||||
entityBinder.setWhere( clazzToProcess.getAnnotation( Where.class ) );
|
||||
entityBinder.setCache( determineCacheSettings( clazzToProcess, context ) );
|
||||
entityBinder.setNaturalIdCache( clazzToProcess, clazzToProcess.getAnnotation( NaturalIdCache.class ) );
|
||||
applyCacheSettings( entityBinder, clazzToProcess, context );
|
||||
|
||||
bindFilters( clazzToProcess, entityBinder, context );
|
||||
|
||||
|
@ -1158,80 +1153,19 @@ public final class AnnotationBinder {
|
|||
}
|
||||
}
|
||||
|
||||
private static Cache determineCacheSettings(XClass clazzToProcess, MetadataBuildingContext context) {
|
||||
Cache cacheAnn = clazzToProcess.getAnnotation( Cache.class );
|
||||
if ( cacheAnn != null ) {
|
||||
return cacheAnn;
|
||||
}
|
||||
private static void applyCacheSettings(EntityBinder binder, XClass clazzToProcess, MetadataBuildingContext context) {
|
||||
binder.applyCaching(
|
||||
clazzToProcess,
|
||||
determineSharedCacheMode( context ),
|
||||
context
|
||||
|
||||
Cacheable cacheableAnn = clazzToProcess.getAnnotation( Cacheable.class );
|
||||
SharedCacheMode mode = determineSharedCacheMode( context );
|
||||
switch ( mode ) {
|
||||
case ALL: {
|
||||
cacheAnn = buildCacheMock( clazzToProcess.getName(), context );
|
||||
break;
|
||||
}
|
||||
case ENABLE_SELECTIVE: {
|
||||
if ( cacheableAnn != null && cacheableAnn.value() ) {
|
||||
cacheAnn = buildCacheMock( clazzToProcess.getName(), context );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DISABLE_SELECTIVE: {
|
||||
if ( cacheableAnn == null || cacheableAnn.value() ) {
|
||||
cacheAnn = buildCacheMock( clazzToProcess.getName(), context );
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// treat both NONE and UNSPECIFIED the same
|
||||
break;
|
||||
}
|
||||
}
|
||||
return cacheAnn;
|
||||
);
|
||||
}
|
||||
|
||||
private static SharedCacheMode determineSharedCacheMode(MetadataBuildingContext context) {
|
||||
return context.getBuildingOptions().getSharedCacheMode();
|
||||
}
|
||||
|
||||
private static Cache buildCacheMock(String region, MetadataBuildingContext context) {
|
||||
return new LocalCacheAnnotationImpl( region, determineCacheConcurrencyStrategy( context ) );
|
||||
}
|
||||
|
||||
private static CacheConcurrencyStrategy determineCacheConcurrencyStrategy(MetadataBuildingContext context) {
|
||||
return CacheConcurrencyStrategy.fromAccessType(
|
||||
context.getBuildingOptions().getImplicitCacheAccessType()
|
||||
);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "ClassExplicitlyAnnotation" })
|
||||
private static class LocalCacheAnnotationImpl implements Cache {
|
||||
private final String region;
|
||||
private final CacheConcurrencyStrategy usage;
|
||||
|
||||
private LocalCacheAnnotationImpl(String region, CacheConcurrencyStrategy usage) {
|
||||
this.region = region;
|
||||
this.usage = usage;
|
||||
}
|
||||
|
||||
public CacheConcurrencyStrategy usage() {
|
||||
return usage;
|
||||
}
|
||||
|
||||
public String region() {
|
||||
return region;
|
||||
}
|
||||
|
||||
public String include() {
|
||||
return "all";
|
||||
}
|
||||
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return Cache.class;
|
||||
}
|
||||
}
|
||||
|
||||
private static PersistentClass makePersistentClass(
|
||||
InheritanceState inheritanceState,
|
||||
PersistentClass superEntity,
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.cfg.annotations;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
@ -15,7 +16,6 @@ import javax.persistence.Access;
|
|||
import javax.persistence.Cacheable;
|
||||
import javax.persistence.ConstraintMode;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.InheritanceType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.NamedEntityGraph;
|
||||
|
@ -23,6 +23,7 @@ import javax.persistence.NamedEntityGraphs;
|
|||
import javax.persistence.PrimaryKeyJoinColumn;
|
||||
import javax.persistence.SecondaryTable;
|
||||
import javax.persistence.SecondaryTables;
|
||||
import javax.persistence.SharedCacheMode;
|
||||
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.AssertionFailure;
|
||||
|
@ -127,17 +128,19 @@ public class EntityBinder {
|
|||
// atm we use both from here; HBM binding solely uses InFlightMetadataCollector.EntityTableXref
|
||||
private java.util.Map<String, Join> secondaryTables = new HashMap<String, Join>();
|
||||
private java.util.Map<String, Object> secondaryTableJoins = new HashMap<String, Object>();
|
||||
private String cacheConcurrentStrategy;
|
||||
private String cacheRegion;
|
||||
private String naturalIdCacheRegion;
|
||||
private List<Filter> filters = new ArrayList<Filter>();
|
||||
private InheritanceState inheritanceState;
|
||||
private boolean ignoreIdAnnotations;
|
||||
private boolean cacheLazyProperty;
|
||||
private AccessType propertyAccessType = AccessType.DEFAULT;
|
||||
private boolean wrapIdsInEmbeddedComponents;
|
||||
private String subselect;
|
||||
|
||||
private boolean isCached;
|
||||
private String cacheConcurrentStrategy;
|
||||
private String cacheRegion;
|
||||
private boolean cacheLazyProperty;
|
||||
private String naturalIdCacheRegion;
|
||||
|
||||
public boolean wrapIdsInEmbeddedComponents() {
|
||||
return wrapIdsInEmbeddedComponents;
|
||||
}
|
||||
|
@ -281,17 +284,25 @@ public class EntityBinder {
|
|||
}
|
||||
rootClass.setMutable( mutable );
|
||||
rootClass.setExplicitPolymorphism( isExplicitPolymorphism( polymorphismType ) );
|
||||
if ( StringHelper.isNotEmpty( where ) ) rootClass.setWhere( where );
|
||||
|
||||
if ( StringHelper.isNotEmpty( where ) ) {
|
||||
rootClass.setWhere( where );
|
||||
}
|
||||
|
||||
if ( cacheConcurrentStrategy != null ) {
|
||||
rootClass.setCacheConcurrencyStrategy( cacheConcurrentStrategy );
|
||||
rootClass.setCacheRegionName( cacheRegion );
|
||||
rootClass.setLazyPropertiesCacheable( cacheLazyProperty );
|
||||
}
|
||||
|
||||
rootClass.setNaturalIdCacheRegionName( naturalIdCacheRegion );
|
||||
|
||||
boolean forceDiscriminatorInSelects = forceDiscriminator == null
|
||||
? context.getBuildingOptions().shouldImplicitlyForceDiscriminatorInSelect()
|
||||
: forceDiscriminator;
|
||||
|
||||
rootClass.setForceDiscriminator( forceDiscriminatorInSelects );
|
||||
|
||||
if ( insertableDiscriminator != null ) {
|
||||
rootClass.setDiscriminatorInsertable( insertableDiscriminator );
|
||||
}
|
||||
|
@ -303,11 +314,10 @@ public class EntityBinder {
|
|||
if (annotatedClass.isAnnotationPresent(Immutable.class)) {
|
||||
LOG.immutableAnnotationOnNonRoot(annotatedClass.getName());
|
||||
}
|
||||
if ( annotatedClass.isAnnotationPresent( Cacheable.class ) ||
|
||||
annotatedClass.isAnnotationPresent( Cache.class ) ) {
|
||||
LOG.cacheOrCacheableAnnotationOnNonRoot( annotatedClass.getName() );
|
||||
}
|
||||
}
|
||||
|
||||
persistentClass.setCached( isCached );
|
||||
|
||||
persistentClass.setOptimisticLockStyle( getVersioning( optimisticLockType ) );
|
||||
persistentClass.setSelectBeforeUpdate( selectBeforeUpdate );
|
||||
|
||||
|
@ -542,6 +552,164 @@ public class EntityBinder {
|
|||
this.wrapIdsInEmbeddedComponents = wrapIdsInEmbeddedComponents;
|
||||
}
|
||||
|
||||
public void applyCaching(
|
||||
XClass clazzToProcess,
|
||||
SharedCacheMode sharedCacheMode,
|
||||
MetadataBuildingContext context) {
|
||||
final Cache explicitCacheAnn = clazzToProcess.getAnnotation( Cache.class );
|
||||
final Cacheable explicitCacheableAnn = clazzToProcess.getAnnotation( Cacheable.class );
|
||||
|
||||
isCached = false;
|
||||
cacheConcurrentStrategy = null;
|
||||
cacheRegion = null;
|
||||
cacheLazyProperty = true;
|
||||
|
||||
if ( persistentClass instanceof RootClass ) {
|
||||
Cache effectiveCacheAnn = explicitCacheAnn;
|
||||
|
||||
if ( explicitCacheAnn != null ) {
|
||||
// preserve legacy behavior of circumventing SharedCacheMode when Hibernate's @Cache is used.
|
||||
isCached = true;
|
||||
}
|
||||
else {
|
||||
effectiveCacheAnn = buildCacheMock( clazzToProcess.getName(), context );
|
||||
|
||||
switch ( sharedCacheMode ) {
|
||||
case ALL: {
|
||||
// all entities should be cached
|
||||
isCached = true;
|
||||
break;
|
||||
}
|
||||
case ENABLE_SELECTIVE: {
|
||||
if ( explicitCacheableAnn != null && explicitCacheableAnn.value() ) {
|
||||
isCached = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DISABLE_SELECTIVE: {
|
||||
if ( explicitCacheableAnn == null || explicitCacheableAnn.value() ) {
|
||||
isCached = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// treat both NONE and UNSPECIFIED the same
|
||||
isCached = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cacheConcurrentStrategy = effectiveCacheAnn.usage().name();
|
||||
cacheRegion = effectiveCacheAnn.region();
|
||||
switch ( effectiveCacheAnn.include().toLowerCase( Locale.ROOT ) ) {
|
||||
case "all": {
|
||||
cacheLazyProperty = true;
|
||||
break;
|
||||
}
|
||||
case "non-lazy": {
|
||||
cacheLazyProperty = false;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new AnnotationException(
|
||||
"Unknown @Cache.include value [" + effectiveCacheAnn.include() + "] : "
|
||||
+ annotatedClass.getName()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( explicitCacheAnn != null ) {
|
||||
LOG.cacheOrCacheableAnnotationOnNonRoot( persistentClass.getClassName() );
|
||||
}
|
||||
else if ( explicitCacheableAnn == null && persistentClass.getSuperclass() != null ) {
|
||||
// we should inherit our super's caching config
|
||||
isCached = persistentClass.getSuperclass().isCached();
|
||||
}
|
||||
else {
|
||||
switch ( sharedCacheMode ) {
|
||||
case ALL: {
|
||||
// all entities should be cached
|
||||
isCached = true;
|
||||
break;
|
||||
}
|
||||
case ENABLE_SELECTIVE: {
|
||||
// only entities with @Cacheable(true) should be cached
|
||||
if ( explicitCacheableAnn != null && explicitCacheableAnn.value() ) {
|
||||
isCached = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DISABLE_SELECTIVE: {
|
||||
if ( explicitCacheableAnn == null || !explicitCacheableAnn.value() ) {
|
||||
isCached = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// treat both NONE and UNSPECIFIED the same
|
||||
isCached = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
naturalIdCacheRegion = null;
|
||||
|
||||
final NaturalIdCache naturalIdCacheAnn = clazzToProcess.getAnnotation( NaturalIdCache.class );
|
||||
if ( naturalIdCacheAnn != null ) {
|
||||
if ( BinderHelper.isEmptyAnnotationValue( naturalIdCacheAnn.region() ) ) {
|
||||
if ( explicitCacheAnn != null && StringHelper.isNotEmpty( explicitCacheAnn.region() ) ) {
|
||||
naturalIdCacheRegion = explicitCacheAnn.region() + NATURAL_ID_CACHE_SUFFIX;
|
||||
}
|
||||
else {
|
||||
naturalIdCacheRegion = clazzToProcess.getName() + NATURAL_ID_CACHE_SUFFIX;
|
||||
}
|
||||
}
|
||||
else {
|
||||
naturalIdCacheRegion = naturalIdCacheAnn.region();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Cache buildCacheMock(String region, MetadataBuildingContext context) {
|
||||
return new LocalCacheAnnotationStub( region, determineCacheConcurrencyStrategy( context ) );
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "ClassExplicitlyAnnotation" })
|
||||
private static class LocalCacheAnnotationStub implements Cache {
|
||||
private final String region;
|
||||
private final CacheConcurrencyStrategy usage;
|
||||
|
||||
private LocalCacheAnnotationStub(String region, CacheConcurrencyStrategy usage) {
|
||||
this.region = region;
|
||||
this.usage = usage;
|
||||
}
|
||||
|
||||
public CacheConcurrencyStrategy usage() {
|
||||
return usage;
|
||||
}
|
||||
|
||||
public String region() {
|
||||
return region;
|
||||
}
|
||||
|
||||
public String include() {
|
||||
return "all";
|
||||
}
|
||||
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return Cache.class;
|
||||
}
|
||||
}
|
||||
|
||||
private static CacheConcurrencyStrategy determineCacheConcurrencyStrategy(MetadataBuildingContext context) {
|
||||
return CacheConcurrencyStrategy.fromAccessType(
|
||||
context.getBuildingOptions().getImplicitCacheAccessType()
|
||||
);
|
||||
}
|
||||
|
||||
private static class EntityTableObjectNameSource implements ObjectNameSource {
|
||||
private final String explicitName;
|
||||
|
@ -1044,48 +1212,6 @@ public class EntityBinder {
|
|||
return secondaryTables;
|
||||
}
|
||||
|
||||
public void setCache(Cache cacheAnn) {
|
||||
if ( cacheAnn != null ) {
|
||||
cacheRegion = BinderHelper.isEmptyAnnotationValue( cacheAnn.region() ) ?
|
||||
null :
|
||||
cacheAnn.region();
|
||||
cacheConcurrentStrategy = getCacheConcurrencyStrategy( cacheAnn.usage() );
|
||||
if ( "all".equalsIgnoreCase( cacheAnn.include() ) ) {
|
||||
cacheLazyProperty = true;
|
||||
}
|
||||
else if ( "non-lazy".equalsIgnoreCase( cacheAnn.include() ) ) {
|
||||
cacheLazyProperty = false;
|
||||
}
|
||||
else {
|
||||
throw new AnnotationException( "Unknown lazy property annotations: " + cacheAnn.include() );
|
||||
}
|
||||
}
|
||||
else {
|
||||
cacheConcurrentStrategy = null;
|
||||
cacheRegion = null;
|
||||
cacheLazyProperty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void setNaturalIdCache(XClass clazzToProcess, NaturalIdCache naturalIdCacheAnn) {
|
||||
if ( naturalIdCacheAnn != null ) {
|
||||
if ( BinderHelper.isEmptyAnnotationValue( naturalIdCacheAnn.region() ) ) {
|
||||
if (cacheRegion != null) {
|
||||
naturalIdCacheRegion = cacheRegion + NATURAL_ID_CACHE_SUFFIX;
|
||||
}
|
||||
else {
|
||||
naturalIdCacheRegion = clazzToProcess.getName() + NATURAL_ID_CACHE_SUFFIX;
|
||||
}
|
||||
}
|
||||
else {
|
||||
naturalIdCacheRegion = naturalIdCacheAnn.region();
|
||||
}
|
||||
}
|
||||
else {
|
||||
naturalIdCacheRegion = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getCacheConcurrencyStrategy(CacheConcurrencyStrategy strategy) {
|
||||
org.hibernate.cache.spi.access.AccessType accessType = strategy.toAccessType();
|
||||
return accessType == null ? null : accessType.getExternalName();
|
||||
|
|
|
@ -1670,7 +1670,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
@Override
|
||||
public void registerInsertedKey(EntityPersister persister, Serializable id) {
|
||||
// we only are worried about registering these if the persister defines caching
|
||||
if ( persister.hasCache() ) {
|
||||
if ( persister.canWriteToCache() ) {
|
||||
if ( insertedKeysMap == null ) {
|
||||
insertedKeysMap = new HashMap<>();
|
||||
}
|
||||
|
@ -1687,7 +1687,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
@Override
|
||||
public boolean wasInsertedDuringTransaction(EntityPersister persister, Serializable id) {
|
||||
// again, we only really care if the entity is cached
|
||||
if ( persister.hasCache() ) {
|
||||
if ( persister.canWriteToCache() ) {
|
||||
if ( insertedKeysMap != null ) {
|
||||
final List<Serializable> insertedEntityIds = insertedKeysMap.get( persister.getRootEntityName() );
|
||||
if ( insertedEntityIds != null ) {
|
||||
|
|
|
@ -183,7 +183,7 @@ public final class TwoPhaseLoad {
|
|||
persister.setPropertyValues( entity, hydratedState );
|
||||
|
||||
final SessionFactoryImplementor factory = session.getFactory();
|
||||
if ( persister.hasCache() && session.getCacheMode().isPutEnabled() ) {
|
||||
if ( persister.canWriteToCache() && session.getCacheMode().isPutEnabled() ) {
|
||||
|
||||
if ( debugEnabled ) {
|
||||
LOG.debugf(
|
||||
|
|
|
@ -215,7 +215,7 @@ public class BatchFetchQueue {
|
|||
|
||||
private boolean isCached(EntityKey entityKey, EntityPersister persister) {
|
||||
final SharedSessionContractImplementor session = context.getSession();
|
||||
if ( context.getSession().getCacheMode().isGetEnabled() && persister.hasCache() ) {
|
||||
if ( context.getSession().getCacheMode().isGetEnabled() && persister.canReadFromCache() ) {
|
||||
final EntityRegionAccessStrategy cache = persister.getCacheAccessStrategy();
|
||||
final Object key = cache.generateCacheKey(
|
||||
entityKey.getIdentifier(),
|
||||
|
|
|
@ -61,7 +61,7 @@ public abstract class AbstractLockUpgradeEventListener extends AbstractReassocia
|
|||
);
|
||||
}
|
||||
|
||||
final boolean cachingEnabled = persister.hasCache();
|
||||
final boolean cachingEnabled = persister.canWriteToCache();
|
||||
SoftLock lock = null;
|
||||
Object ck = null;
|
||||
try {
|
||||
|
|
|
@ -385,7 +385,7 @@ public class DefaultLoadEventListener extends AbstractLockUpgradeEventListener i
|
|||
SoftLock lock = null;
|
||||
final Object ck;
|
||||
final EntityRegionAccessStrategy cache = persister.getCacheAccessStrategy();
|
||||
if ( persister.hasCache() ) {
|
||||
if ( persister.canWriteToCache() ) {
|
||||
ck = cache.generateCacheKey(
|
||||
event.getEntityId(),
|
||||
persister,
|
||||
|
@ -403,7 +403,7 @@ public class DefaultLoadEventListener extends AbstractLockUpgradeEventListener i
|
|||
entity = load( event, persister, keyToLoad, options );
|
||||
}
|
||||
finally {
|
||||
if ( persister.hasCache() ) {
|
||||
if ( persister.canWriteToCache() ) {
|
||||
cache.unlockItem( source, ck, lock );
|
||||
}
|
||||
}
|
||||
|
@ -583,7 +583,7 @@ public class DefaultLoadEventListener extends AbstractLockUpgradeEventListener i
|
|||
final EntityKey entityKey) {
|
||||
|
||||
final SessionImplementor source = event.getSession();
|
||||
final boolean useCache = persister.hasCache()
|
||||
final boolean useCache = persister.canReadFromCache()
|
||||
&& source.getCacheMode().isGetEnabled()
|
||||
&& event.getLockMode().lessThan( LockMode.READ );
|
||||
|
||||
|
|
|
@ -144,7 +144,7 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
|
|||
}
|
||||
}
|
||||
|
||||
if ( persister.hasCache() ) {
|
||||
if ( persister.canWriteToCache() ) {
|
||||
Object previousVersion = null;
|
||||
if ( persister.isVersionPropertyGenerated() ) {
|
||||
// we need to grab the version value from the entity, otherwise
|
||||
|
|
|
@ -629,15 +629,6 @@ public class FromElement extends HqlSqlWalkerNode implements DisplayableNode, Pa
|
|||
this.withClauseFragment = withClauseFragment;
|
||||
}
|
||||
|
||||
public boolean hasCacheablePersister() {
|
||||
if ( getQueryableCollection() != null ) {
|
||||
return getQueryableCollection().hasCache();
|
||||
}
|
||||
else {
|
||||
return getQueryable().hasCache();
|
||||
}
|
||||
}
|
||||
|
||||
public void handlePropertyBeingDereferenced(Type propertySource, String propertyName) {
|
||||
if ( getQueryableCollection() != null && CollectionProperties.isCollectionProperty( propertyName ) ) {
|
||||
// propertyName refers to something like collection.size...
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.hibernate.internal.util.collections.ArrayHelper;
|
|||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.RootClass;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.pretty.MessageHelper;
|
||||
|
@ -119,7 +120,7 @@ public class CacheImpl implements CacheImplementor {
|
|||
@Override
|
||||
public boolean containsEntity(String entityName, Serializable identifier) {
|
||||
EntityPersister p = sessionFactory.getMetamodel().entityPersister( entityName );
|
||||
if ( p.hasCache() ) {
|
||||
if ( p.canReadFromCache() ) {
|
||||
EntityRegionAccessStrategy cache = p.getCacheAccessStrategy();
|
||||
Object key = cache.generateCacheKey( identifier, p, sessionFactory, null ); // have to assume non tenancy
|
||||
return cache.getRegion().contains( key );
|
||||
|
@ -137,7 +138,7 @@ public class CacheImpl implements CacheImplementor {
|
|||
@Override
|
||||
public void evictEntity(String entityName, Serializable identifier) {
|
||||
EntityPersister p = sessionFactory.getMetamodel().entityPersister( entityName );
|
||||
if ( p.hasCache() ) {
|
||||
if ( p.canWriteToCache() ) {
|
||||
if ( LOG.isDebugEnabled() ) {
|
||||
LOG.debugf(
|
||||
"Evicting second-level cache: %s",
|
||||
|
@ -158,7 +159,7 @@ public class CacheImpl implements CacheImplementor {
|
|||
@Override
|
||||
public void evictEntityRegion(String entityName) {
|
||||
EntityPersister p = sessionFactory.getMetamodel().entityPersister( entityName );
|
||||
if ( p.hasCache() ) {
|
||||
if ( p.canWriteToCache() ) {
|
||||
if ( LOG.isDebugEnabled() ) {
|
||||
LOG.debugf( "Evicting second-level cache: %s", p.getEntityName() );
|
||||
}
|
||||
|
@ -428,12 +429,23 @@ public class CacheImpl implements CacheImplementor {
|
|||
throw new PersistenceException( "Hibernate cannot unwrap Cache as " + cls.getName() );
|
||||
}
|
||||
|
||||
// todo (5.3) : normalize caching to the "first subclass" in the hierarchy whose subclasses all define caching
|
||||
// 5.3 adds support for "subclass only" caching, so we need a different paradigm for
|
||||
// code such as this that assumes root-only caching
|
||||
|
||||
@Override
|
||||
public EntityRegionAccessStrategy determineEntityRegionAccessStrategy(PersistentClass model) {
|
||||
final String cacheRegionName = cacheRegionPrefix + model.getRootClass().getCacheRegionName();
|
||||
if ( ! settings.isSecondLevelCacheEnabled() ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// cache settings are defined on root entity
|
||||
final RootClass rootEntity = model.getRootClass();
|
||||
|
||||
final String cacheRegionName = cacheRegionPrefix + rootEntity.getCacheRegionName();
|
||||
EntityRegionAccessStrategy accessStrategy = entityRegionAccessStrategyMap.get( cacheRegionName );
|
||||
if ( accessStrategy == null && settings.isSecondLevelCacheEnabled() ) {
|
||||
final AccessType accessType = AccessType.fromExternalName( model.getCacheConcurrencyStrategy() );
|
||||
if ( accessStrategy == null ) {
|
||||
final AccessType accessType = AccessType.fromExternalName( rootEntity.getCacheConcurrencyStrategy() );
|
||||
if ( accessType != null ) {
|
||||
LOG.tracef( "Building shared cache region for entity data [%s]", model.getEntityName() );
|
||||
EntityRegion entityRegion = regionFactory.buildEntityRegion(
|
||||
|
|
|
@ -1768,7 +1768,7 @@ public interface CoreMessageLogger extends BasicLogger {
|
|||
void unknownJavaTypeNoEqualsHashCode(Class javaType);
|
||||
|
||||
@LogMessage(level = WARN)
|
||||
@Message(value = "@javax.persistence.Cacheable or @org.hibernate.annotations.Cache used on a non-root entity: ignored for %s", id = 482)
|
||||
@Message(value = "@org.hibernate.annotations.Cache used on a non-root entity: ignored for %s", id = 482)
|
||||
void cacheOrCacheableAnnotationOnNonRoot(String className);
|
||||
|
||||
@LogMessage(level = WARN)
|
||||
|
|
|
@ -219,7 +219,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
|
|||
// );
|
||||
// }
|
||||
|
||||
if ( persister.hasCache() ) {
|
||||
if ( persister.canWriteToCache() ) {
|
||||
final EntityRegionAccessStrategy cache = persister.getCacheAccessStrategy();
|
||||
final Object ck = cache.generateCacheKey( id, persister, getFactory(), getTenantIdentifier() );
|
||||
cache.evict( ck );
|
||||
|
|
|
@ -90,6 +90,8 @@ public abstract class PersistentClass implements AttributeContainer, Serializabl
|
|||
private Component declaredIdentifierMapper;
|
||||
private OptimisticLockStyle optimisticLockStyle;
|
||||
|
||||
private boolean isCached;
|
||||
|
||||
public PersistentClass(MetadataBuildingContext metadataBuildingContext) {
|
||||
this.metadataBuildingContext = metadataBuildingContext;
|
||||
}
|
||||
|
@ -270,10 +272,35 @@ public abstract class PersistentClass implements AttributeContainer, Serializabl
|
|||
|
||||
public abstract boolean isVersioned();
|
||||
|
||||
public abstract String getNaturalIdCacheRegionName();
|
||||
|
||||
public boolean isCached() {
|
||||
return isCached;
|
||||
}
|
||||
|
||||
public void setCached(boolean cached) {
|
||||
isCached = cached;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use {@link #isCached} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isCachingExplicitlyRequested() {
|
||||
return isCached();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use {@link #setCached} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setCachingExplicitlyRequested(boolean cached) {
|
||||
setCached( cached );
|
||||
}
|
||||
|
||||
public abstract String getCacheConcurrencyStrategy();
|
||||
|
||||
public abstract String getNaturalIdCacheRegionName();
|
||||
|
||||
public abstract PersistentClass getSuperclass();
|
||||
|
||||
public abstract boolean isExplicitPolymorphism();
|
||||
|
@ -955,8 +982,6 @@ public abstract class PersistentClass implements AttributeContainer, Serializabl
|
|||
return false;
|
||||
}
|
||||
|
||||
public abstract boolean isLazyPropertiesCacheable();
|
||||
|
||||
// The following methods are added to support @MappedSuperclass in the metamodel
|
||||
public Iterator getDeclaredPropertyIterator() {
|
||||
ArrayList iterators = new ArrayList();
|
||||
|
|
|
@ -34,10 +34,12 @@ public class RootClass extends PersistentClass implements TableOwner {
|
|||
private KeyValue identifier;
|
||||
private Property version;
|
||||
private boolean polymorphic;
|
||||
|
||||
private String cacheConcurrencyStrategy;
|
||||
private String cacheRegionName;
|
||||
private String naturalIdCacheRegionName;
|
||||
private boolean lazyPropertiesCacheable = true;
|
||||
private String naturalIdCacheRegionName;
|
||||
|
||||
private Value discriminator;
|
||||
private boolean mutable = true;
|
||||
private boolean embeddedIdentifier;
|
||||
|
@ -50,7 +52,6 @@ public class RootClass extends PersistentClass implements TableOwner {
|
|||
private int nextSubclassId;
|
||||
private Property declaredIdentifierProperty;
|
||||
private Property declaredVersion;
|
||||
private boolean cachingExplicitlyRequested;
|
||||
|
||||
public RootClass(MetadataBuildingContext metadataBuildingContext) {
|
||||
super( metadataBuildingContext );
|
||||
|
@ -314,6 +315,14 @@ public class RootClass extends PersistentClass implements TableOwner {
|
|||
this.cacheRegionName = cacheRegionName;
|
||||
}
|
||||
|
||||
public boolean isLazyPropertiesCacheable() {
|
||||
return lazyPropertiesCacheable;
|
||||
}
|
||||
|
||||
public void setLazyPropertiesCacheable(boolean lazyPropertiesCacheable) {
|
||||
this.lazyPropertiesCacheable = lazyPropertiesCacheable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNaturalIdCacheRegionName() {
|
||||
return naturalIdCacheRegionName;
|
||||
|
@ -323,15 +332,6 @@ public class RootClass extends PersistentClass implements TableOwner {
|
|||
this.naturalIdCacheRegionName = naturalIdCacheRegionName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLazyPropertiesCacheable() {
|
||||
return lazyPropertiesCacheable;
|
||||
}
|
||||
|
||||
public void setLazyPropertiesCacheable(boolean lazyPropertiesCacheable) {
|
||||
this.lazyPropertiesCacheable = lazyPropertiesCacheable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJoinedSubclass() {
|
||||
return false;
|
||||
|
@ -360,11 +360,4 @@ public class RootClass extends PersistentClass implements TableOwner {
|
|||
return mv.accept( this );
|
||||
}
|
||||
|
||||
public void setCachingExplicitlyRequested(boolean explicitlyRequested) {
|
||||
this.cachingExplicitlyRequested = explicitlyRequested;
|
||||
}
|
||||
|
||||
public boolean isCachingExplicitlyRequested() {
|
||||
return cachingExplicitlyRequested;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ public class Subclass extends PersistentClass {
|
|||
}
|
||||
|
||||
public String getCacheConcurrencyStrategy() {
|
||||
return getSuperclass().getCacheConcurrencyStrategy();
|
||||
return getRootClass().getCacheConcurrencyStrategy();
|
||||
}
|
||||
|
||||
public RootClass getRootClass() {
|
||||
|
@ -190,10 +190,6 @@ public class Subclass extends PersistentClass {
|
|||
this.classPersisterClass = classPersisterClass;
|
||||
}
|
||||
|
||||
public boolean isLazyPropertiesCacheable() {
|
||||
return getSuperclass().isLazyPropertiesCacheable();
|
||||
}
|
||||
|
||||
public int getJoinClosureSpan() {
|
||||
return getSuperclass().getJoinClosureSpan() + super.getJoinClosureSpan();
|
||||
}
|
||||
|
|
|
@ -97,6 +97,7 @@ import org.hibernate.mapping.Component;
|
|||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Selectable;
|
||||
import org.hibernate.mapping.Subclass;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.metadata.ClassMetadata;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
|
@ -148,6 +149,8 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
// moved up from AbstractEntityPersister ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
private final SessionFactoryImplementor factory;
|
||||
private final boolean canReadFromCache;
|
||||
private final boolean canWriteToCache;
|
||||
private final EntityRegionAccessStrategy cacheAccessStrategy;
|
||||
private final NaturalIdRegionAccessStrategy naturalIdRegionAccessStrategy;
|
||||
private final boolean isLazyPropertiesCacheable;
|
||||
|
@ -512,9 +515,21 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
// moved up from AbstractEntityPersister ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
this.factory = creationContext.getSessionFactory();
|
||||
|
||||
if ( creationContext.getSessionFactory().getSessionFactoryOptions().isSecondLevelCacheEnabled() ) {
|
||||
this.canWriteToCache = persistentClass.isCached();
|
||||
this.canReadFromCache = determineCanReadFromCache( persistentClass );
|
||||
this.cacheAccessStrategy = cacheAccessStrategy;
|
||||
this.isLazyPropertiesCacheable = persistentClass.getRootClass().isLazyPropertiesCacheable();
|
||||
this.naturalIdRegionAccessStrategy = naturalIdRegionAccessStrategy;
|
||||
isLazyPropertiesCacheable = persistentClass.isLazyPropertiesCacheable();
|
||||
}
|
||||
else {
|
||||
this.canWriteToCache = false;
|
||||
this.canReadFromCache = false;
|
||||
this.cacheAccessStrategy = null;
|
||||
this.isLazyPropertiesCacheable = true;
|
||||
this.naturalIdRegionAccessStrategy = null;
|
||||
}
|
||||
|
||||
this.entityMetamodel = new EntityMetamodel( persistentClass, this, factory );
|
||||
this.entityTuplizer = this.entityMetamodel.getTuplizer();
|
||||
|
@ -830,6 +845,22 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private boolean determineCanReadFromCache(PersistentClass persistentClass) {
|
||||
if ( persistentClass.isCached() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final Iterator<Subclass> subclassIterator = persistentClass.getSubclassIterator();
|
||||
while ( subclassIterator.hasNext() ) {
|
||||
final Subclass subclass = subclassIterator.next();
|
||||
if ( subclass.isCached() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected CacheEntryHelper buildCacheEntryHelper() {
|
||||
if ( cacheAccessStrategy == null ) {
|
||||
// the entity defined no caching...
|
||||
|
@ -985,7 +1016,7 @@ public abstract class AbstractEntityPersister
|
|||
);
|
||||
}
|
||||
|
||||
if ( session.getCacheMode().isGetEnabled() && hasCache() && isLazyPropertiesCacheable() ) {
|
||||
if ( session.getCacheMode().isGetEnabled() && canReadFromCache() && isLazyPropertiesCacheable() ) {
|
||||
final EntityRegionAccessStrategy cache = getCacheAccessStrategy();
|
||||
final Object cacheKey = cache.generateCacheKey(id, this, session.getFactory(), session.getTenantIdentifier() );
|
||||
final Object ce = CacheHelper.fromSharedCache( session, cacheKey, cache );
|
||||
|
@ -4293,8 +4324,18 @@ public abstract class AbstractEntityPersister
|
|||
return entityMetamodel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canReadFromCache() {
|
||||
return canReadFromCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWriteToCache() {
|
||||
return canWriteToCache;
|
||||
}
|
||||
|
||||
public boolean hasCache() {
|
||||
return cacheAccessStrategy != null;
|
||||
return canWriteToCache;
|
||||
}
|
||||
|
||||
public EntityRegionAccessStrategy getCacheAccessStrategy() {
|
||||
|
@ -4467,7 +4508,7 @@ public abstract class AbstractEntityPersister
|
|||
}
|
||||
|
||||
// check to see if it is in the second-level cache
|
||||
if ( session.getCacheMode().isGetEnabled() && hasCache() ) {
|
||||
if ( session.getCacheMode().isGetEnabled() && canReadFromCache() ) {
|
||||
final EntityRegionAccessStrategy cache = getCacheAccessStrategy();
|
||||
final Object ck = cache.generateCacheKey( id, this, session.getFactory(), session.getTenantIdentifier() );
|
||||
final Object ce = CacheHelper.fromSharedCache( session, ck, getCacheAccessStrategy() );
|
||||
|
|
|
@ -503,9 +503,16 @@ public interface EntityPersister extends OptimisticCacheSource, EntityDefinition
|
|||
* Should lazy properties of this entity be cached?
|
||||
*/
|
||||
boolean isLazyPropertiesCacheable();
|
||||
|
||||
boolean canReadFromCache();
|
||||
boolean canWriteToCache();
|
||||
|
||||
/**
|
||||
* Does this class have a cache.
|
||||
*
|
||||
* @deprecated Use {@link #canReadFromCache()} and/or {@link #canWriteToCache()} depending on need
|
||||
*/
|
||||
@Deprecated
|
||||
boolean hasCache();
|
||||
/**
|
||||
* Get the cache (optional operation)
|
||||
|
|
|
@ -13,7 +13,6 @@ import javax.persistence.EntityManagerFactory;
|
|||
import javax.persistence.SharedCacheMode;
|
||||
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.cache.internal.NoCachingRegionFactory;
|
||||
import org.hibernate.cache.spi.access.AccessType;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.jpa.AvailableSettings;
|
||||
|
@ -24,12 +23,11 @@ import org.hibernate.mapping.PersistentClass;
|
|||
|
||||
import org.hibernate.testing.cache.CachingRegionFactory;
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* this is hacky transient step until EMF building is integrated with metamodel
|
||||
|
@ -51,13 +49,13 @@ public class ConfigurationTest extends BaseUnitTestCase {
|
|||
MetadataImplementor metadata = buildMetadata( SharedCacheMode.NONE );
|
||||
|
||||
PersistentClass pc = metadata.getEntityBinding( ExplicitlyCacheableEntity.class.getName() );
|
||||
assertNull( pc.getCacheConcurrencyStrategy() );
|
||||
assertFalse( pc.isCached() );
|
||||
|
||||
pc = metadata.getEntityBinding( ExplicitlyNonCacheableEntity.class.getName() );
|
||||
assertNull( pc.getCacheConcurrencyStrategy() );
|
||||
assertFalse( pc.isCached() );
|
||||
|
||||
pc = metadata.getEntityBinding( NoCacheableAnnotationEntity.class.getName() );
|
||||
assertNull( pc.getCacheConcurrencyStrategy() );
|
||||
assertFalse( pc.isCached() );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -65,13 +63,13 @@ public class ConfigurationTest extends BaseUnitTestCase {
|
|||
MetadataImplementor metadata = buildMetadata( SharedCacheMode.UNSPECIFIED );
|
||||
|
||||
PersistentClass pc = metadata.getEntityBinding( ExplicitlyCacheableEntity.class.getName() );
|
||||
assertNull( pc.getCacheConcurrencyStrategy() );
|
||||
assertFalse( pc.isCached() );
|
||||
|
||||
pc = metadata.getEntityBinding( ExplicitlyNonCacheableEntity.class.getName() );
|
||||
assertNull( pc.getCacheConcurrencyStrategy() );
|
||||
assertFalse( pc.isCached() );
|
||||
|
||||
pc = metadata.getEntityBinding( NoCacheableAnnotationEntity.class.getName() );
|
||||
assertNull( pc.getCacheConcurrencyStrategy() );
|
||||
assertFalse( pc.isCached() );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -79,13 +77,13 @@ public class ConfigurationTest extends BaseUnitTestCase {
|
|||
MetadataImplementor metadata = buildMetadata( SharedCacheMode.ALL );
|
||||
|
||||
PersistentClass pc = metadata.getEntityBinding( ExplicitlyCacheableEntity.class.getName() );
|
||||
assertNotNull( pc.getCacheConcurrencyStrategy() );
|
||||
assertTrue( pc.isCached() );
|
||||
|
||||
pc = metadata.getEntityBinding( ExplicitlyNonCacheableEntity.class.getName() );
|
||||
assertNotNull( pc.getCacheConcurrencyStrategy() );
|
||||
assertTrue( pc.isCached() );
|
||||
|
||||
pc = metadata.getEntityBinding( NoCacheableAnnotationEntity.class.getName() );
|
||||
assertNotNull( pc.getCacheConcurrencyStrategy() );
|
||||
assertTrue( pc.isCached() );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -93,13 +91,13 @@ public class ConfigurationTest extends BaseUnitTestCase {
|
|||
MetadataImplementor metadata = buildMetadata( SharedCacheMode.ENABLE_SELECTIVE );
|
||||
|
||||
PersistentClass pc = metadata.getEntityBinding( ExplicitlyCacheableEntity.class.getName() );
|
||||
assertNotNull( pc.getCacheConcurrencyStrategy() );
|
||||
assertTrue( pc.isCached() );
|
||||
|
||||
pc = metadata.getEntityBinding( ExplicitlyNonCacheableEntity.class.getName() );
|
||||
assertNull( pc.getCacheConcurrencyStrategy() );
|
||||
assertFalse( pc.isCached() );
|
||||
|
||||
pc = metadata.getEntityBinding( NoCacheableAnnotationEntity.class.getName() );
|
||||
assertNull( pc.getCacheConcurrencyStrategy() );
|
||||
assertFalse( pc.isCached() );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -107,13 +105,13 @@ public class ConfigurationTest extends BaseUnitTestCase {
|
|||
MetadataImplementor metadata = buildMetadata( SharedCacheMode.DISABLE_SELECTIVE );
|
||||
|
||||
PersistentClass pc = metadata.getEntityBinding( ExplicitlyCacheableEntity.class.getName() );
|
||||
assertNotNull( pc.getCacheConcurrencyStrategy() );
|
||||
assertTrue( pc.isCached() );
|
||||
|
||||
pc = metadata.getEntityBinding( ExplicitlyNonCacheableEntity.class.getName() );
|
||||
assertNull( pc.getCacheConcurrencyStrategy() );
|
||||
assertFalse( pc.isCached() );
|
||||
|
||||
pc = metadata.getEntityBinding( NoCacheableAnnotationEntity.class.getName() );
|
||||
assertNotNull( pc.getCacheConcurrencyStrategy() );
|
||||
assertTrue( pc.isCached() );
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
|
@ -411,6 +411,16 @@ public class PersisterClassProviderTest {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canReadFromCache() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWriteToCache() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCache() {
|
||||
return false;
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.junit.Test;
|
|||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
|
@ -65,7 +66,7 @@ public class NonRootEntityWithCacheAnnotationTest {
|
|||
.buildMetadata();
|
||||
|
||||
assertTrue( triggerable.wasTriggered() );
|
||||
assertNull( ( metadata.getEntityBinding( AEntity.class.getName() ) ).getCacheConcurrencyStrategy() );
|
||||
assertFalse( metadata.getEntityBinding( AEntity.class.getName() ).isCached() );
|
||||
|
||||
serviceRegistry.destroy();
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ import org.junit.Test;
|
|||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
|
@ -64,8 +64,10 @@ public class NonRootEntityWithCacheableAnnotationTest {
|
|||
.addAnnotatedClass( AEntity.class )
|
||||
.buildMetadata();
|
||||
|
||||
assertTrue( triggerable.wasTriggered() );
|
||||
assertNull( ( metadata.getEntityBinding( AEntity.class.getName() ) ).getCacheConcurrencyStrategy() );
|
||||
assertFalse( metadata.getEntityBinding( ABase.class.getName() ).isCached() );
|
||||
assertTrue( metadata.getEntityBinding( AEntity.class.getName() ).isCached() );
|
||||
|
||||
assertFalse( triggerable.wasTriggered() );
|
||||
|
||||
serviceRegistry.destroy();
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ public class PolymorphicCacheTest extends BaseCoreFunctionalTestCase {
|
|||
s.beginTransaction();
|
||||
// See HHH-9107
|
||||
try {
|
||||
s.get( CachedItem2.class, item1.getId() );
|
||||
final CachedItem2 tmp = s.get( CachedItem2.class, item1.getId() );
|
||||
fail( "Expected a WrongClassException to be thrown." );
|
||||
}
|
||||
catch (WrongClassException e) {
|
||||
|
|
|
@ -28,7 +28,9 @@ import org.hibernate.testing.junit4.BaseUnitTestCase;
|
|||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
|
@ -60,6 +62,8 @@ public class DefaultCacheConcurrencyPropertyTest extends BaseUnitTestCase {
|
|||
final SessionFactoryImplementor sf = (SessionFactoryImplementor) metadata.buildSessionFactory();
|
||||
try {
|
||||
final EntityPersister persister = sf.getMetamodel().entityPersister( TheEntity.class.getName() );
|
||||
assertTrue( persister.canReadFromCache() );
|
||||
assertTrue( persister.canWriteToCache() );
|
||||
assertNotNull( persister.getCacheAccessStrategy() );
|
||||
}
|
||||
finally {
|
||||
|
|
|
@ -384,6 +384,16 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canReadFromCache() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWriteToCache() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCache() {
|
||||
return false;
|
||||
|
|
|
@ -6,22 +6,89 @@
|
|||
*/
|
||||
package org.hibernate.test.jpa.compliance.tck2_2;
|
||||
|
||||
import java.util.Map;
|
||||
import javax.persistence.Cacheable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Inheritance;
|
||||
import javax.persistence.InheritanceType;
|
||||
import javax.persistence.SharedCacheMode;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hamcrest.CoreMatchers;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SubclassOnlyCachingTests extends BaseNonConfigCoreFunctionalTestCase {
|
||||
@Test
|
||||
public void testMapping() {
|
||||
assertThat(
|
||||
sessionFactory().getMetamodel().entityPersister( Person.class ).hasCache(),
|
||||
CoreMatchers.is( false )
|
||||
);
|
||||
assertThat(
|
||||
sessionFactory().getMetamodel().entityPersister( Employee.class ).hasCache(),
|
||||
CoreMatchers.is( false )
|
||||
);
|
||||
assertThat(
|
||||
sessionFactory().getMetamodel().entityPersister( Customer.class ).hasCache(),
|
||||
CoreMatchers.is( true )
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnlySubclassIsCached() {
|
||||
final StatisticsImplementor statistics = sessionFactory().getStatistics();
|
||||
|
||||
inTransaction(
|
||||
s -> s.persist( new Customer( 1, "Acme Corp", "123" ) )
|
||||
);
|
||||
|
||||
assertTrue( sessionFactory().getCache().contains( Customer.class, 1 ) );
|
||||
|
||||
inTransaction(
|
||||
s -> {
|
||||
statistics.clear();
|
||||
|
||||
final Customer customer = s.get( Customer.class, 1 );
|
||||
|
||||
assertTrue( Hibernate.isInitialized( customer ) );
|
||||
|
||||
assertThat( statistics.getSecondLevelCacheHitCount(), CoreMatchers.is(1L) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanupData() {
|
||||
inTransaction(
|
||||
s -> s.createQuery( "delete from Customer" ).executeUpdate()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addSettings(Map settings) {
|
||||
super.addSettings( settings );
|
||||
|
||||
settings.put( AvailableSettings.USE_SECOND_LEVEL_CACHE, "true" );
|
||||
settings.put( AvailableSettings.GENERATE_STATISTICS, "true" );
|
||||
settings.put( AvailableSettings.JPA_SHARED_CACHE_MODE, SharedCacheMode.ENABLE_SELECTIVE );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyMetadataSources(MetadataSources sources) {
|
||||
|
@ -31,11 +98,6 @@ public class SubclassOnlyCachingTests extends BaseNonConfigCoreFunctionalTestCas
|
|||
sources.addAnnotatedClass( Customer.class );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnlySubclassIsCached() {
|
||||
|
||||
}
|
||||
|
||||
@Entity( name = "Person" )
|
||||
@Table( name = "persons" )
|
||||
@Inheritance( strategy = InheritanceType.SINGLE_TABLE )
|
||||
|
@ -43,18 +105,43 @@ public class SubclassOnlyCachingTests extends BaseNonConfigCoreFunctionalTestCas
|
|||
@Id
|
||||
public Integer id;
|
||||
public String name;
|
||||
|
||||
public Person() {
|
||||
}
|
||||
|
||||
@Entity
|
||||
public Person(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "Employee" )
|
||||
public static class Employee extends Person {
|
||||
public String employeeCode;
|
||||
public String costCenter;
|
||||
|
||||
public Employee() {
|
||||
}
|
||||
|
||||
@Entity
|
||||
public Employee(Integer id, String name, String employeeCode, String costCenter) {
|
||||
super( id, name );
|
||||
this.employeeCode = employeeCode;
|
||||
this.costCenter = costCenter;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "Customer" )
|
||||
@Cacheable()
|
||||
public static class Customer extends Person {
|
||||
public String erpCode;
|
||||
|
||||
public Customer() {
|
||||
}
|
||||
|
||||
public Customer(Integer id, String name, String erpCode) {
|
||||
super( id, name );
|
||||
this.erpCode = erpCode;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -653,6 +653,16 @@ public class CustomPersister implements EntityPersister {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canReadFromCache() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWriteToCache() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVersionPropertyGenerated() {
|
||||
return false;
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.hibernate.cfg.Environment;
|
|||
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
|
||||
import org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.RootClass;
|
||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||
import org.hibernate.tool.schema.internal.HibernateSchemaManagementTool;
|
||||
|
@ -70,7 +71,9 @@ public class DiscriminatorMultiTenancyTest extends BaseUnitTestCase {
|
|||
ms.addAnnotatedClass(Customer.class);
|
||||
|
||||
Metadata metadata = ms.buildMetadata();
|
||||
((RootClass) metadata.getEntityBinding(Customer.class.getName())).setCacheConcurrencyStrategy("read-write");
|
||||
final PersistentClass customerMapping = metadata.getEntityBinding( Customer.class.getName() );
|
||||
customerMapping.setCached( true );
|
||||
((RootClass) customerMapping ).setCacheConcurrencyStrategy( "read-write");
|
||||
|
||||
HibernateSchemaManagementTool tool = new HibernateSchemaManagementTool();
|
||||
tool.injectServices(serviceRegistry);
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.hibernate.cfg.Environment;
|
|||
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
|
||||
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.RootClass;
|
||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||
import org.hibernate.service.spi.Stoppable;
|
||||
|
@ -74,7 +75,9 @@ public abstract class AbstractSchemaBasedMultiTenancyTest<T extends MultiTenantC
|
|||
ms.addAnnotatedClass( Invoice.class );
|
||||
|
||||
Metadata metadata = ms.buildMetadata();
|
||||
( (RootClass) metadata.getEntityBinding( Customer.class.getName() ) ).setCacheConcurrencyStrategy( "read-write" );
|
||||
final PersistentClass customerMapping = metadata.getEntityBinding( Customer.class.getName() );
|
||||
customerMapping.setCached( true );
|
||||
( (RootClass) customerMapping ).setCacheConcurrencyStrategy( "read-write" );
|
||||
|
||||
HibernateSchemaManagementTool tool = new HibernateSchemaManagementTool();
|
||||
tool.injectServices( serviceRegistry );
|
||||
|
|
|
@ -344,6 +344,7 @@ public class BaseNonConfigCoreFunctionalTestCase extends BaseUnitTestCase {
|
|||
|
||||
if ( !hasLob ) {
|
||||
( ( RootClass) entityBinding ).setCacheConcurrencyStrategy( getCacheConcurrencyStrategy() );
|
||||
entityBinding.setCached( true );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue