HHH-17188 Eagerly select values when query cache is enabled

This commit is contained in:
Marco Belladelli 2023-09-20 11:03:06 +02:00
parent c84a30c2c5
commit c0c628f16c
8 changed files with 66 additions and 3 deletions

View File

@ -668,6 +668,13 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
return result;
}
@Override
public void resolveState(RowProcessingState rowProcessingState) {
for ( DomainResultAssembler<?> subAssembler : subAssemblers ) {
subAssembler.resolveState( rowProcessingState );
}
}
@Override
public JavaType<Object[]> getAssembledJavaType() {
return jtd;

View File

@ -38,4 +38,12 @@ public interface DomainResultAssembler<J> {
* assembles.
*/
JavaType<J> getAssembledJavaType();
/**
* This method is used to resolve the assembler's state, i.e. reading the result values,
* with some performance optimization when we don't need the result object itself
*/
default void resolveState(RowProcessingState rowProcessingState) {
assemble( rowProcessingState );
}
}

View File

@ -84,6 +84,11 @@ public class BasicResultAssembler<J> implements DomainResultAssembler<J> {
return (J) jdbcValue;
}
@Override
public void resolveState(RowProcessingState rowProcessingState) {
extractRawValue( rowProcessingState );
}
@Override
public JavaType<J> getAssembledJavaType() {
if ( valueConverter != null ) {

View File

@ -323,6 +323,15 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
state = stateAllNull ? State.NULL : State.EXTRACTED;
}
@Override
public void resolveState(RowProcessingState rowProcessingState) {
if ( determinInitialState() == State.INITIAL ) {
for ( final DomainResultAssembler<?> assembler : assemblers ) {
assembler.resolveState( rowProcessingState );
}
}
}
private Object createCompositeInstance(NavigablePath navigablePath, SessionFactoryImplementor sessionFactory) {
if ( state == State.NULL ) {
// todo (6.0) : should we initialize the composite instance if it has a parent attribute?

View File

@ -48,4 +48,6 @@ public interface EmbeddableInitializer extends FetchParentAccess {
default EmbeddableInitializer asEmbeddableInitializer() {
return this;
}
void resolveState(RowProcessingState rowProcessingState);
}

View File

@ -28,6 +28,7 @@ import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParentAccess;
import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.Initializer;
import org.hibernate.sql.results.graph.embeddable.AbstractEmbeddableInitializer;
import org.hibernate.sql.results.graph.embeddable.EmbeddableInitializer;
import org.hibernate.sql.results.graph.embeddable.EmbeddableLoadingLogger;
import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode;
@ -158,9 +159,7 @@ public abstract class AbstractNonAggregatedIdentifierMappingInitializer extends
return;
case INITIAL:
// If we don't have an id class and this is a find by id lookup, we just use that instance
if ( !hasIdClass && processingState.getEntityId() != null
&& navigablePath.getParent().getParent() == null
&& navigablePath instanceof EntityIdentifierNavigablePath ) {
if ( isFindByIdLookup( processingState ) ) {
compositeInstance = processingState.getEntityId();
state = State.INJECTED;
return;
@ -216,6 +215,12 @@ public abstract class AbstractNonAggregatedIdentifierMappingInitializer extends
}
}
private boolean isFindByIdLookup(RowProcessingState processingState) {
return !hasIdClass && processingState.getEntityId() != null
&& navigablePath.getParent().getParent() == null
&& navigablePath instanceof EntityIdentifierNavigablePath;
}
private void extractRowState(RowProcessingState processingState) {
state = State.NULL;
for ( int i = 0; i < assemblers.length; i++ ) {
@ -256,6 +261,15 @@ public abstract class AbstractNonAggregatedIdentifierMappingInitializer extends
state = State.EXTRACTED;
}
@Override
public void resolveState(RowProcessingState rowProcessingState) {
if ( !isFindByIdLookup( rowProcessingState ) ) {
for ( final DomainResultAssembler<?> assembler : assemblers ) {
assembler.resolveState( rowProcessingState );
}
}
}
@Override
public Object[] getValues() {
return state == State.NULL ? null : idClassState;

View File

@ -35,4 +35,10 @@ public class EmbeddableAssembler implements DomainResultAssembler {
return initializer.getCompositeInstance();
}
@Override
public void resolveState(RowProcessingState rowProcessingState) {
// use resolveState instead of initialize instance to avoid
// unneeded embeddable instantiation and injection
initializer.resolveState( rowProcessingState );
}
}

View File

@ -517,6 +517,10 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
this.isInitialized = true;
registerReloadedEntity( rowProcessingState, existingEntity );
notifyResolutionListeners( entityInstance );
if ( rowProcessingState.getQueryOptions().isResultCachingEnabled() == Boolean.TRUE ) {
// We still need to read result set values to correctly populate the query cache
resolveState( rowProcessingState );
}
}
else {
registerLoadingEntityInstanceFromExecutionContext( rowProcessingState, entityInstance );
@ -1062,6 +1066,14 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
return values;
}
private void resolveState(RowProcessingState rowProcessingState) {
for ( final DomainResultAssembler<?> assembler : assemblers[concreteDescriptor.getSubclassId()] ) {
if ( assembler != null ) {
assembler.resolveState( rowProcessingState );
}
}
}
protected boolean skipInitialization(Object toInitialize, RowProcessingState rowProcessingState) {
if ( !isOwningInitializer ) {
return true;