HHH-15393 - Improve write-paths to use mapping model

This commit is contained in:
Steve Ebersole 2022-11-29 12:40:30 -06:00
parent 7461100c39
commit 94e2b599e4
9 changed files with 46 additions and 106 deletions

View File

@ -8,14 +8,9 @@ package org.hibernate.engine.jdbc.mutation.internal;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.function.Supplier;
import org.hibernate.engine.jdbc.batch.spi.Batch;
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
import org.hibernate.engine.jdbc.mutation.JdbcValueBindings;
import org.hibernate.engine.jdbc.mutation.MutationExecutor;
import org.hibernate.engine.jdbc.mutation.OperationResultChecker;
@ -59,26 +54,14 @@ public class MutationExecutorPostInsert implements MutationExecutor {
private final PreparedStatementDetails identityInsertStatementDetails;
/**
* The batched statements
*/
private final Batch batch;
/**
* Any non-batched JDBC statements
*/
private final PreparedStatementGroup nonBatchedStatementGroup;
private final PreparedStatementGroup secondaryTablesStatementGroup;
private final JdbcValueBindingsImpl valueBindings;
private enum StatementLocation { IDENTITY, BATCHED, NON_BATCHED }
private final Map<String, StatementLocation> statementLocationMap = new HashMap<>();
public MutationExecutorPostInsert(
MutationOperationGroup mutationOperationGroup,
Supplier<BatchKey> batchKeySupplier,
int batchSize,
SharedSessionContractImplementor session) {
public MutationExecutorPostInsert(MutationOperationGroup mutationOperationGroup, SharedSessionContractImplementor session) {
this.mutationTarget = (EntityMutationTarget) mutationOperationGroup.getMutationTarget();
this.valueBindings = new JdbcValueBindingsImpl(
MutationType.INSERT,
@ -92,12 +75,8 @@ public class MutationExecutorPostInsert implements MutationExecutor {
identityInsertOperation,
session
);
statementLocationMap.put( mutationTarget.getIdentifierTableName(), StatementLocation.IDENTITY );
final BatchKey batchKey = batchKeySupplier.get();
List<PreparableMutationOperation> batchedJdbcMutations = null;
List<PreparableMutationOperation> nonBatchedJdbcMutations = null;
List<PreparableMutationOperation> secondaryTableMutations = null;
final List<MutationOperation> operations = mutationOperationGroup.getOperations();
for ( int i = 0; i < operations.size(); i++ ) {
@ -112,48 +91,17 @@ public class MutationExecutorPostInsert implements MutationExecutor {
assert ! (operation instanceof SelfExecutingUpdateOperation );
final PreparableMutationOperation preparableMutationOperation = (PreparableMutationOperation) operation;
if ( preparableMutationOperation.canBeBatched( batchKey, batchSize ) ) {
if ( batchedJdbcMutations == null ) {
batchedJdbcMutations = new ArrayList<>();
}
batchedJdbcMutations.add( preparableMutationOperation );
statementLocationMap.put( operation.getTableDetails().getTableName(), StatementLocation.BATCHED );
}
else {
if ( nonBatchedJdbcMutations == null ) {
nonBatchedJdbcMutations = new ArrayList<>();
}
nonBatchedJdbcMutations.add( preparableMutationOperation );
statementLocationMap.put( operation.getTableDetails().getTableName(), StatementLocation.NON_BATCHED );
if ( secondaryTableMutations == null ) {
secondaryTableMutations = new ArrayList<>();
}
secondaryTableMutations.add( preparableMutationOperation );
}
// todo (mutation) : consider creating single PreparedStatementGroup for all
// batched and non-batched statements. we then need a way to know whether a
// statement is batched or not. `PreparedStatementDetails#isBatched`?
if ( batchedJdbcMutations == null || batchedJdbcMutations.isEmpty() ) {
this.batch = null;
}
else {
final List<PreparableMutationOperation> batchedMutationsRef = batchedJdbcMutations;
this.batch = session.getJdbcCoordinator().getBatch2(
batchKey,
batchSize,
() -> ModelMutationHelper.toPreparedStatementGroup(
MutationType.INSERT,
mutationTarget,
batchedMutationsRef,
session
)
);
assert batch != null;
}
this.nonBatchedStatementGroup = ModelMutationHelper.toPreparedStatementGroup(
this.secondaryTablesStatementGroup = ModelMutationHelper.toPreparedStatementGroup(
MutationType.INSERT,
mutationTarget,
nonBatchedJdbcMutations,
secondaryTableMutations,
session
);
}
@ -174,27 +122,11 @@ public class MutationExecutorPostInsert implements MutationExecutor {
@Override
public PreparedStatementDetails getPreparedStatementDetails(String tableName) {
final StatementLocation statementLocation = statementLocationMap.get( tableName );
if ( statementLocation == null ) {
return null;
}
if ( statementLocation == StatementLocation.IDENTITY ) {
assert mutationTarget.getIdentifierTableName().equals( tableName );
if ( mutationTarget.getIdentifierTableName().equals( tableName ) ) {
return identityInsertStatementDetails;
}
if ( statementLocation == StatementLocation.BATCHED ) {
assert batch != null;
return batch.getStatementGroup().getPreparedStatementDetails( tableName );
}
if ( statementLocation == StatementLocation.NON_BATCHED ) {
assert nonBatchedStatementGroup != null;
return nonBatchedStatementGroup.getPreparedStatementDetails( tableName );
}
return null;
return secondaryTablesStatementGroup.getPreparedStatementDetails( tableName );
}
@Override
@ -215,19 +147,8 @@ public class MutationExecutorPostInsert implements MutationExecutor {
);
}
if ( nonBatchedStatementGroup != null ) {
nonBatchedStatementGroup.forEachStatement( (tableName, statementDetails) -> executeWithId(
id,
tableName,
statementDetails,
inclusionChecker,
resultChecker,
session
) );
}
if ( batch != null ) {
batch.getStatementGroup().forEachStatement( (tableName, statementDetails) -> executeWithId(
if ( secondaryTablesStatementGroup != null ) {
secondaryTablesStatementGroup.forEachStatement( (tableName, statementDetails) -> executeWithId(
id,
tableName,
statementDetails,
@ -301,7 +222,7 @@ public class MutationExecutorPostInsert implements MutationExecutor {
@Override
public void release() {
nonBatchedStatementGroup.release();
secondaryTablesStatementGroup.release();
}
@Override

View File

@ -69,6 +69,6 @@ public class MutationExecutorServiceInitiator implements StandardServiceInitiato
}
private MutationExecutorService createStandardService(Map<String, Object> configurationValues, ServiceRegistryImplementor registry) {
return new StandardMutationExecutorService( configurationValues, registry );
return new StandardMutationExecutorService( configurationValues );
}
}

View File

@ -188,7 +188,6 @@ public class MutationExecutorStandard extends AbstractMutationExecutor {
@Override
public void release() {
nonBatchedStatementGroup.release();
// todo (mutation) :implement
}
@Override

View File

@ -51,12 +51,6 @@ public class PreparedStatementDetailsStandard implements PreparedStatementDetail
Supplier<PreparedStatement> jdbcStatementCreator,
Expectation expectation,
JdbcServices jdbcServices) {
// todo (mutation) : have `parameterDescriptors` be passed in.
// - these descriptors being only available relative solely
// to a preparable operation, rather than more widely scoped to
// the `MutationOperation`, causes problems for self-executing operations
this.mutatingTableDetails = tableMutation.getTableDetails();
this.sql = sql;
this.jdbcStatementCreator = jdbcStatementCreator;

View File

@ -17,7 +17,6 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.persister.entity.mutation.EntityMutationTarget;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.sql.model.MutationOperation;
import org.hibernate.sql.model.MutationOperationGroup;
import org.hibernate.sql.model.MutationTarget;
@ -35,7 +34,7 @@ import org.hibernate.sql.model.SelfExecutingUpdateOperation;
public class StandardMutationExecutorService implements MutationExecutorService {
private final int globalBatchSize;
public StandardMutationExecutorService(Map<String, Object> configurationValues, ServiceRegistryImplementor registry) {
public StandardMutationExecutorService(Map<String, Object> configurationValues) {
this( ConfigurationHelper.getInt( Environment.STATEMENT_BATCH_SIZE, configurationValues, 1 ) );
}
@ -66,7 +65,7 @@ public class StandardMutationExecutorService implements MutationExecutorService
assert mutationTarget instanceof EntityMappingType;
if ( numberOfOperations > 1 ) {
return new MutationExecutorPostInsert( operationGroup, batchKeySupplier, batchSizeToUse, session );
return new MutationExecutorPostInsert( operationGroup, session );
}
return new MutationExecutorPostInsertSingleTable( operationGroup, session );

View File

@ -11,4 +11,7 @@
*
* @author Steve Ebersole
*/
@Incubating
package org.hibernate.engine.jdbc.mutation;
import org.hibernate.Incubating;

View File

@ -7,12 +7,15 @@
/**
* Defines support for performing mutation operations against collections.
* <p/>
* The names used here are logical. E.g. "inserting a row" may actually
*
* @apiNote The names used here are logical. E.g. "inserting a row" may actually
* execute an UPDATE statement instead of an INSERT. This is generally
* delineated based on whether there is a collection table involved or
* not. In standard Hibernate terms, this breaks down to the distinction
* between {@link org.hibernate.persister.collection.BasicCollectionPersister}
* and {@link org.hibernate.persister.collection.OneToManyPersister}.
*/
@Incubating
package org.hibernate.persister.collection.mutation;
import org.hibernate.Incubating;

View File

@ -0,0 +1,17 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
*/
/**
* Defines support for performing mutation operations originating
* from persistence-context events
*
* @author Steve Ebersole
*/
@Incubating
package org.hibernate.persister.entity.mutation;
import org.hibernate.Incubating;

View File

@ -77,7 +77,11 @@ public interface MutationOperation {
TableMapping getTableDetails();
/**
* Find the JDBC parameter to be used for the specified column
* Find the JDBC parameter to be used for the specified column.
*
* @return The descriptor, or null if none match.
*
* @see #getJdbcValueDescriptor
*/
JdbcValueDescriptor findValueDescriptor(String columnName, ParameterUsage usage);