Skip to content

Commit

Permalink
HHH-12282 - Allow disabling of invalidation of second-level cache ent…
Browse files Browse the repository at this point in the history
…ries for multi-table entities
  • Loading branch information
sebersole committed Feb 13, 2018
1 parent 5e397e9 commit 8cfe412
Show file tree
Hide file tree
Showing 9 changed files with 326 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1212,6 +1212,14 @@ public void enableJpaClosedCompliance(boolean enabled) {
this.jpaCompliance.setClosedCompliance( enabled );
}

public void enableJpaProxyCompliance(boolean enabled) {
this.jpaCompliance.setProxyCompliance( enabled );
}

public void enableJpaCachingCompliance(boolean enabled) {
this.jpaCompliance.setCachingCompliance( enabled );
}

public void markAsJpaBootstrap() {
this.jpaBootstrap = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1834,6 +1834,12 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings {
*/
String JPA_PROXY_COMPLIANCE = "hibernate.jpa.compliance.proxy";

/**
* @see JpaCompliance#isJpaCacheComplianceEnabled()
* @since 5.3
*/
String JPA_CACHING_COMPLIANCE = "hibernate.jpa.compliance.caching";

/**
* True/False setting indicating if the value stored in the table used by the {@link javax.persistence.TableGenerator}
* is the last value generated or the next value to be used.
Expand Down
12 changes: 12 additions & 0 deletions hibernate-core/src/main/java/org/hibernate/jpa/JpaCompliance.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,16 @@ public interface JpaCompliance {
* @return {@code true} indicates to behave in the spec-defined way
*/
boolean isJpaProxyComplianceEnabled();

/**
* Should Hibernate comply with all aspects of caching as defined by JPA? Or can
* it deviate to perform things it believes will be "better"?
*
* @implNote Effects include marking all secondary tables as non-optional. The reason
* being that optional secondary tables can lead to entity cache being invalidated rather
* than updated.
*
* @return {@code true} says to act the spec-defined way.
*/
boolean isJpaCacheComplianceEnabled();
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public class JpaComplianceImpl implements JpaCompliance {
private boolean listCompliance;
private boolean closedCompliance;
private boolean proxyCompliance;
private boolean cachingCompliance;


@SuppressWarnings("ConstantConditions")
Expand Down Expand Up @@ -52,6 +53,11 @@ public JpaComplianceImpl(Map configurationSettings, boolean jpaByDefault) {
configurationSettings,
jpaByDefault
);
cachingCompliance = ConfigurationHelper.getBoolean(
AvailableSettings.JPA_CACHING_COMPLIANCE,
configurationSettings,
jpaByDefault
);
}

@Override
Expand Down Expand Up @@ -79,6 +85,11 @@ public boolean isJpaProxyComplianceEnabled() {
return proxyCompliance;
}

@Override
public boolean isJpaCacheComplianceEnabled() {
return cachingCompliance;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Mutators

Expand All @@ -97,4 +108,12 @@ public void setListCompliance(boolean listCompliance) {
public void setClosedCompliance(boolean closedCompliance) {
this.closedCompliance = closedCompliance;
}

public void setProxyCompliance(boolean proxyCompliance) {
this.proxyCompliance = proxyCompliance;
}

public void setCachingCompliance(boolean cachingCompliance) {
this.cachingCompliance = cachingCompliance;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.Formula;
import org.hibernate.mapping.Join;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Selectable;
Expand Down Expand Up @@ -152,6 +153,7 @@ public abstract class AbstractEntityPersister
private final SessionFactoryImplementor factory;
private final boolean canReadFromCache;
private final boolean canWriteToCache;
private final boolean invalidateCache;
private final EntityRegionAccessStrategy cacheAccessStrategy;
private final NaturalIdRegionAccessStrategy naturalIdRegionAccessStrategy;
private final boolean isLazyPropertiesCacheable;
Expand Down Expand Up @@ -845,6 +847,50 @@ public AbstractEntityPersister(

this.cacheEntryHelper = buildCacheEntryHelper();

if ( creationContext.getSessionFactory().getSessionFactoryOptions().isSecondLevelCacheEnabled() ) {
this.invalidateCache = canWriteToCache && determineWhetherToInvalidateCache( persistentClass, creationContext );
}
else {
this.invalidateCache = false;
}

}

@SuppressWarnings("RedundantIfStatement")
private boolean determineWhetherToInvalidateCache(
PersistentClass persistentClass,
PersisterCreationContext creationContext) {
if ( hasFormulaProperties() ) {
return true;
}

if ( isVersioned() ) {
return false;
}

if ( entityMetamodel.isDynamicUpdate() ) {
return false;
}

// We need to check whether the user may have circumvented this logic (JPA TCK)
final boolean complianceEnabled = creationContext.getSessionFactory()
.getSessionFactoryOptions()
.getJpaCompliance()
.isJpaCacheComplianceEnabled();
if ( complianceEnabled ) {
// The JPA TCK (inadvertently, but still...) requires that we cache
// entities with secondary tables even though Hibernate historically
// invalidated them
return false;
}

if ( persistentClass.getJoinClosureSpan() >= 1 ) {
// todo : this should really consider optionality of the secondary tables in count
// non-optional tables do not cause this bypass
return true;
}

return false;
}

@SuppressWarnings("unchecked")
Expand Down Expand Up @@ -1273,8 +1319,7 @@ protected boolean[] getSubclassFormulaLazyiness() {
* item.
*/
public boolean isCacheInvalidationRequired() {
return hasFormulaProperties() ||
( !isVersioned() && ( entityMetamodel.isDynamicUpdate() || getTableSpan() > 1 ) );
return invalidateCache;
}

public boolean isLazyPropertiesCacheable() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,12 @@ else if ( persistentClass.isDiscriminatorValueNotNull() ) {
while ( joinItr.hasNext() ) {
Join join = (Join) joinItr.next();

isNullableTable[tableIndex++] = join.isOptional();
isNullableTable[tableIndex++] = join.isOptional() ||
creationContext.getSessionFactory()
.getSessionFactoryOptions()
.getJpaCompliance()
.isJpaCacheComplianceEnabled();


Table table = join.getTable();
final String tableName = determineTableName( table, jdbcEnvironment );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,11 @@ public SingleTableEntityPersister(
Join join = (Join) joinIter.next();
qualifiedTableNames[j] = determineTableName( join.getTable(), jdbcEnvironment );
isInverseTable[j] = join.isInverse();
isNullableTable[j] = join.isOptional();
isNullableTable[j] = join.isOptional()
|| creationContext.getSessionFactory()
.getSessionFactoryOptions()
.getJpaCompliance()
.isJpaCacheComplianceEnabled();
cascadeDeleteEnabled[j] = join.getKey().isCascadeDeleteEnabled() &&
factory.getDialect().supportsCascadeDelete();

Expand Down Expand Up @@ -244,7 +248,12 @@ public SingleTableEntityPersister(
isConcretes.add( persistentClass.isClassOrSuperclassJoin( join ) );
isDeferreds.add( join.isSequentialSelect() );
isInverses.add( join.isInverse() );
isNullables.add( join.isOptional() );
isNullables.add(
join.isOptional() || creationContext.getSessionFactory()
.getSessionFactoryOptions()
.getJpaCompliance()
.isJpaCacheComplianceEnabled()
);
isLazies.add( lazyAvailable && join.isLazy() );
if ( join.isSequentialSelect() && !persistentClass.isClassOrSuperclassJoin( join ) ) {
hasDeferred = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public static JpaCompliance withClosedCompliance() {
private boolean listCompliance;
private boolean closedCompliance;
private boolean proxyCompliance;
private boolean cacheCompliance;

@Override
public boolean isJpaQueryComplianceEnabled() {
Expand All @@ -68,4 +69,9 @@ public boolean isJpaClosedComplianceEnabled() {
public boolean isJpaProxyComplianceEnabled() {
return proxyCompliance;
}

@Override
public boolean isJpaCacheComplianceEnabled() {
return cacheCompliance;
}
}
Loading

0 comments on commit 8cfe412

Please sign in to comment.