Skip to content

Commit

Permalink
HHH-2558 - Allow batching inserts for multi-table entities
Browse files Browse the repository at this point in the history
HHH-5797 - Improve batching for entity updates or deletes that use secondary tables
  • Loading branch information
dcebotarenco authored and vladmihalcea committed Jan 8, 2018
1 parent 6f83e4b commit 50070ea
Show file tree
Hide file tree
Showing 10 changed files with 693 additions and 15 deletions.
Expand Up @@ -31,7 +31,8 @@ public class BatchingBatch extends AbstractBatchImpl {

// IMPL NOTE : Until HHH-5797 is fixed, there will only be 1 statement in a batch

private final int batchSize;
private int batchSize;
private final int configuredBatchSize;
private int batchPosition;
private boolean batchExecuted;
private int statementPosition;
Expand All @@ -52,6 +53,7 @@ public BatchingBatch(
throw new HibernateException( "attempting to batch an operation which cannot be batched" );
}
this.batchSize = batchSize;
this.configuredBatchSize = batchSize;
}

private String currentStatementSql;
Expand All @@ -60,7 +62,12 @@ public BatchingBatch(
@Override
public PreparedStatement getBatchStatement(String sql, boolean callable) {
currentStatementSql = sql;
int previousBatchSize = getStatements().size();
currentStatement = super.getBatchStatement( sql, callable );
int currentBatchSize = getStatements().size();
if ( currentBatchSize > previousBatchSize ) {
this.batchSize = this.configuredBatchSize * currentBatchSize;
}
return currentStatement;
}

Expand Down Expand Up @@ -134,7 +141,7 @@ private void performExecution() {

private void checkRowCounts(int[] rowCounts, PreparedStatement ps) throws SQLException, HibernateException {
final int numberOfRowCounts = rowCounts.length;
if ( numberOfRowCounts != batchPosition ) {
if ( batchPosition != 0 && numberOfRowCounts != batchPosition / getStatements().size() ) {
LOG.unexpectedRowCounts();
}
for ( int i = 0; i < numberOfRowCounts; i++ ) {
Expand Down
Expand Up @@ -74,7 +74,6 @@ public PreparedStatement prepareStatement(String sql) {

@Override
public PreparedStatement prepareStatement(String sql, final boolean isCallable) {
jdbcCoordinator.executeBatch();
return buildPreparedStatementPreparationTemplate( sql, isCallable ).prepareStatement();
}

Expand Down
Expand Up @@ -21,11 +21,13 @@
import org.hibernate.ScrollMode;
import org.hibernate.SharedSessionContract;
import org.hibernate.Transaction;
import org.hibernate.cfg.Environment;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.jdbc.LobCreationContext;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.loader.custom.CustomQuery;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.query.spi.QueryProducerImplementor;
Expand Down Expand Up @@ -421,4 +423,28 @@ default boolean isQueryParametersValidationEnabled(){
LoadQueryInfluencers getLoadQueryInfluencers();

ExceptionConverter getExceptionConverter();

/**
* Get the currently configured JDBC batch size either at the Session-level or SessionFactory-level.
*
* If the Session-level JDBC batch size was not configured, return the SessionFactory-level one.
*
* @return Session-level or or SessionFactory-level JDBC batch size.
*
* @since 5.2
*
* @see org.hibernate.boot.spi.SessionFactoryOptions#getJdbcBatchSize
* @see org.hibernate.boot.SessionFactoryBuilder#applyJdbcBatchSize
*/
default Integer getConfiguredJdbcBatchSize() {
final Integer sessionJdbcBatchSize = getJdbcBatchSize();

return sessionJdbcBatchSize == null ?
ConfigurationHelper.getInt(
Environment.STATEMENT_BATCH_SIZE,
getFactory().getProperties(),
1
) :
sessionJdbcBatchSize;
}
}
Expand Up @@ -196,7 +196,8 @@ protected int doUpdateRows(Serializable id, PersistentCollection collection, Sha
PreparedStatement st = null;
Expectation expectation = Expectations.appropriateExpectation( getUpdateCheckStyle() );
boolean callable = isUpdateCallable();
boolean useBatch = expectation.canBeBatched();
final int jdbcBatchSizeToUse = session.getConfiguredJdbcBatchSize();
boolean useBatch = expectation.canBeBatched() && jdbcBatchSizeToUse > 1;
Iterator entries = collection.entries( this );
String sql = getSQLUpdateRowString();
int i = 0;
Expand Down
Expand Up @@ -3004,10 +3004,9 @@ protected void insert(

// TODO : shouldn't inserts be Expectations.NONE?
final Expectation expectation = Expectations.appropriateExpectation( insertResultCheckStyles[j] );
// we can't batch joined inserts, *especially* not if it is an identity insert;
// nor can we batch statements where the expectation is based on an output param
final boolean useBatch = j == 0 && expectation.canBeBatched();
if ( useBatch && inserBatchKey == null ) {
final int jdbcBatchSizeToUse = session.getConfiguredJdbcBatchSize();
final boolean useBatch = expectation.canBeBatched() && jdbcBatchSizeToUse > 1;
if ( useBatch && inserBatchKey == null) {
inserBatchKey = new BasicBatchKey(
getEntityName() + "#INSERT",
expectation
Expand Down Expand Up @@ -3145,7 +3144,8 @@ protected boolean update(
final SharedSessionContractImplementor session) throws HibernateException {

final Expectation expectation = Expectations.appropriateExpectation( updateResultCheckStyles[j] );
final boolean useBatch = j == 0 && expectation.canBeBatched() && isBatchable(); //note: updates to joined tables can't be batched...
final int jdbcBatchSizeToUse = session.getConfiguredJdbcBatchSize();
final boolean useBatch = expectation.canBeBatched() && isBatchable() && jdbcBatchSizeToUse > 1;
if ( useBatch && updateBatchKey == null ) {
updateBatchKey = new BasicBatchKey(
getEntityName() + "#UPDATE",
Expand Down
Expand Up @@ -71,10 +71,7 @@ public void testBasicInsertion() {
Field field = sessionImplementor.getJdbcCoordinator().getClass().getDeclaredField( "currentBatch" );
field.setAccessible( true );
Batch batch = (Batch) field.get( sessionImplementor.getJdbcCoordinator() );
if ( batch == null ) {
throw new Exception( "Current batch was null" );
}
else {
if ( batch != null ) {
//make sure it's actually a batching impl
assertEquals( NonBatchingBatch.class, batch.getClass() );
field = AbstractBatchImpl.class.getDeclaredField( "statements" );
Expand Down
Expand Up @@ -98,7 +98,7 @@ public void testBatchingAmongstSubClasses() {
connectionProvider.clear();
} );

assertEquals( 26, connectionProvider.getPreparedStatements().size() );
assertEquals( 4, connectionProvider.getPreparedStatements().size() );
}

@Override
Expand Down
Expand Up @@ -99,7 +99,7 @@ public void testBatchingAmongstSubClasses() {
connectionProvider.clear();
} );

assertEquals( 17, connectionProvider.getPreparedStatements().size() );
assertEquals( 10, connectionProvider.getPreparedStatements().size() );
}

@Override
Expand Down

0 comments on commit 50070ea

Please sign in to comment.