HHH-18692 Hibernate attempts to close batched statements multiple times
This commit is contained in:
parent
8524c1e4d6
commit
7e411943cc
|
@ -162,26 +162,11 @@ public class BatchImpl implements Batch {
|
||||||
if ( batchPosition == batchSizeToUse ) {
|
if ( batchPosition == batchSizeToUse ) {
|
||||||
notifyObserversImplicitExecution();
|
notifyObserversImplicitExecution();
|
||||||
performExecution();
|
performExecution();
|
||||||
batchPosition = 0;
|
|
||||||
batchExecuted = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void releaseStatements() {
|
protected void releaseStatements() {
|
||||||
statementGroup.forEachStatement( (tableName, statementDetails) -> {
|
|
||||||
if ( statementDetails.getStatement() == null ) {
|
|
||||||
BATCH_LOGGER.debugf(
|
|
||||||
"PreparedStatementDetails did not contain PreparedStatement on #releaseStatements : %s",
|
|
||||||
statementDetails.getSqlString()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
clearBatch( statementDetails );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
statementGroup.release();
|
statementGroup.release();
|
||||||
jdbcCoordinator.afterStatementExecution();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void clearBatch(PreparedStatementDetails statementDetails) {
|
protected void clearBatch(PreparedStatementDetails statementDetails) {
|
||||||
|
@ -299,8 +284,10 @@ public class BatchImpl implements Batch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
batchExecuted = true;
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
jdbcCoordinator.afterStatementExecution();
|
||||||
batchPosition = 0;
|
batchPosition = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,8 +167,12 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
|
||||||
return currentBatch;
|
return currentBatch;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
currentBatch.execute();
|
try {
|
||||||
currentBatch.release();
|
currentBatch.execute();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
currentBatch.release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,7 +198,12 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
|
||||||
public void conditionallyExecuteBatch(BatchKey key) {
|
public void conditionallyExecuteBatch(BatchKey key) {
|
||||||
if ( currentBatch != null && !currentBatch.getKey().equals( key ) ) {
|
if ( currentBatch != null && !currentBatch.getKey().equals( key ) ) {
|
||||||
JdbcBatchLogging.BATCH_LOGGER.debugf( "Conditionally executing batch - %s", currentBatch.getKey() );
|
JdbcBatchLogging.BATCH_LOGGER.debugf( "Conditionally executing batch - %s", currentBatch.getKey() );
|
||||||
currentBatch.execute();
|
try {
|
||||||
|
currentBatch.execute();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
currentBatch.release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,4 +56,8 @@ public interface PreparedStatementDetails {
|
||||||
}
|
}
|
||||||
|
|
||||||
void releaseStatement(SharedSessionContractImplementor session);
|
void releaseStatement(SharedSessionContractImplementor session);
|
||||||
|
|
||||||
|
default boolean toRelease(){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.engine.jdbc.mutation.internal;
|
||||||
|
|
||||||
|
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
|
||||||
|
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementGroup;
|
||||||
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import static org.hibernate.engine.jdbc.batch.JdbcBatchLogging.BATCH_LOGGER;
|
||||||
|
import static org.hibernate.engine.jdbc.batch.JdbcBatchLogging.BATCH_MESSAGE_LOGGER;
|
||||||
|
|
||||||
|
public abstract class AbstractPreparedStatementGroup implements PreparedStatementGroup {
|
||||||
|
private final SharedSessionContractImplementor session;
|
||||||
|
|
||||||
|
public AbstractPreparedStatementGroup(SharedSessionContractImplementor session) {
|
||||||
|
this.session = session;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void clearBatch(PreparedStatementDetails statementDetails) {
|
||||||
|
final PreparedStatement statement = statementDetails.getStatement();
|
||||||
|
assert statement != null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// This code can be called after the connection is released
|
||||||
|
// and the statement is closed. If the statement is closed,
|
||||||
|
// then SQLException will be thrown when PreparedStatement#clearBatch
|
||||||
|
// is called.
|
||||||
|
// Ensure the statement is not closed before
|
||||||
|
// calling PreparedStatement#clearBatch.
|
||||||
|
if ( !statement.isClosed() ) {
|
||||||
|
statement.clearBatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch ( SQLException e ) {
|
||||||
|
BATCH_MESSAGE_LOGGER.unableToReleaseBatchStatement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void release(PreparedStatementDetails statementDetails) {
|
||||||
|
if ( statementDetails.toRelease() ) {
|
||||||
|
if ( statementDetails.getStatement() == null ) {
|
||||||
|
BATCH_LOGGER.debugf(
|
||||||
|
"PreparedStatementDetails did not contain PreparedStatement on #releaseStatements : %s",
|
||||||
|
statementDetails.getSqlString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
clearBatch( statementDetails );
|
||||||
|
}
|
||||||
|
statementDetails.releaseStatement( session );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,6 +30,8 @@ public class PreparedStatementDetailsStandard implements PreparedStatementDetail
|
||||||
|
|
||||||
private PreparedStatement statement;
|
private PreparedStatement statement;
|
||||||
|
|
||||||
|
private boolean toRelease;
|
||||||
|
|
||||||
public PreparedStatementDetailsStandard(
|
public PreparedStatementDetailsStandard(
|
||||||
PreparableMutationOperation tableMutation,
|
PreparableMutationOperation tableMutation,
|
||||||
Supplier<PreparedStatement> jdbcStatementCreator,
|
Supplier<PreparedStatement> jdbcStatementCreator,
|
||||||
|
@ -66,6 +68,7 @@ public class PreparedStatementDetailsStandard implements PreparedStatementDetail
|
||||||
if ( statement != null ) {
|
if ( statement != null ) {
|
||||||
session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( statement );
|
session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( statement );
|
||||||
statement = null;
|
statement = null;
|
||||||
|
toRelease = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,6 +85,7 @@ public class PreparedStatementDetailsStandard implements PreparedStatementDetail
|
||||||
@Override
|
@Override
|
||||||
public PreparedStatement resolveStatement() {
|
public PreparedStatement resolveStatement() {
|
||||||
if ( statement == null ) {
|
if ( statement == null ) {
|
||||||
|
toRelease = true;
|
||||||
statement = jdbcStatementCreator.get();
|
statement = jdbcStatementCreator.get();
|
||||||
try {
|
try {
|
||||||
expectation.prepare( statement );
|
expectation.prepare( statement );
|
||||||
|
@ -102,6 +106,11 @@ public class PreparedStatementDetailsStandard implements PreparedStatementDetail
|
||||||
return expectation;
|
return expectation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean toRelease() {
|
||||||
|
return toRelease;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "PreparedStatementDetails(" + sql + ")";
|
return "PreparedStatementDetails(" + sql + ")";
|
||||||
|
|
|
@ -8,7 +8,6 @@ import java.util.function.BiConsumer;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
|
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
|
||||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementGroup;
|
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.generator.values.GeneratedValuesMutationDelegate;
|
import org.hibernate.generator.values.GeneratedValuesMutationDelegate;
|
||||||
import org.hibernate.sql.model.PreparableMutationOperation;
|
import org.hibernate.sql.model.PreparableMutationOperation;
|
||||||
|
@ -20,9 +19,8 @@ import org.hibernate.sql.model.TableMapping;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class PreparedStatementGroupSingleTable implements PreparedStatementGroup {
|
public class PreparedStatementGroupSingleTable extends AbstractPreparedStatementGroup {
|
||||||
private final PreparableMutationOperation jdbcMutation;
|
private final PreparableMutationOperation jdbcMutation;
|
||||||
private final SharedSessionContractImplementor session;
|
|
||||||
|
|
||||||
private final PreparedStatementDetails statementDetails;
|
private final PreparedStatementDetails statementDetails;
|
||||||
|
|
||||||
|
@ -36,9 +34,9 @@ public class PreparedStatementGroupSingleTable implements PreparedStatementGroup
|
||||||
PreparableMutationOperation jdbcMutation,
|
PreparableMutationOperation jdbcMutation,
|
||||||
GeneratedValuesMutationDelegate delegate,
|
GeneratedValuesMutationDelegate delegate,
|
||||||
SharedSessionContractImplementor session) {
|
SharedSessionContractImplementor session) {
|
||||||
|
super(session);
|
||||||
this.jdbcMutation = jdbcMutation;
|
this.jdbcMutation = jdbcMutation;
|
||||||
this.statementDetails = ModelMutationHelper.standardPreparation( jdbcMutation, delegate, session );
|
this.statementDetails = ModelMutationHelper.standardPreparation( jdbcMutation, delegate, session );
|
||||||
this.session = session;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TableMapping getMutatingTableDetails() {
|
protected TableMapping getMutatingTableDetails() {
|
||||||
|
@ -89,7 +87,7 @@ public class PreparedStatementGroupSingleTable implements PreparedStatementGroup
|
||||||
@Override
|
@Override
|
||||||
public void release() {
|
public void release() {
|
||||||
if ( statementDetails != null ) {
|
if ( statementDetails != null ) {
|
||||||
statementDetails.releaseStatement( session );
|
release( statementDetails );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@ import java.util.function.Predicate;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
|
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
|
||||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementGroup;
|
|
||||||
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||||
import org.hibernate.engine.jdbc.spi.MutationStatementPreparer;
|
import org.hibernate.engine.jdbc.spi.MutationStatementPreparer;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
@ -32,11 +31,10 @@ import org.hibernate.sql.model.TableMapping;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class PreparedStatementGroupStandard implements PreparedStatementGroup {
|
public class PreparedStatementGroupStandard extends AbstractPreparedStatementGroup {
|
||||||
private final MutationType mutationType;
|
private final MutationType mutationType;
|
||||||
private final MutationTarget<?> mutationTarget;
|
private final MutationTarget<?> mutationTarget;
|
||||||
private final List<PreparableMutationOperation> jdbcMutations;
|
private final List<PreparableMutationOperation> jdbcMutations;
|
||||||
private final SharedSessionContractImplementor session;
|
|
||||||
|
|
||||||
private final SortedMap<String, PreparedStatementDetails> statementMap;
|
private final SortedMap<String, PreparedStatementDetails> statementMap;
|
||||||
|
|
||||||
|
@ -47,11 +45,11 @@ public class PreparedStatementGroupStandard implements PreparedStatementGroup {
|
||||||
GeneratedValuesMutationDelegate generatedValuesDelegate,
|
GeneratedValuesMutationDelegate generatedValuesDelegate,
|
||||||
List<PreparableMutationOperation> jdbcMutations,
|
List<PreparableMutationOperation> jdbcMutations,
|
||||||
SharedSessionContractImplementor session) {
|
SharedSessionContractImplementor session) {
|
||||||
|
super( session );
|
||||||
this.mutationType = mutationType;
|
this.mutationType = mutationType;
|
||||||
this.mutationTarget = mutationTarget;
|
this.mutationTarget = mutationTarget;
|
||||||
this.jdbcMutations = jdbcMutations;
|
this.jdbcMutations = jdbcMutations;
|
||||||
|
|
||||||
this.session = session;
|
|
||||||
|
|
||||||
this.statementMap = createStatementDetailsMap( jdbcMutations, mutationType, generatedValuesDelegate, session );
|
this.statementMap = createStatementDetailsMap( jdbcMutations, mutationType, generatedValuesDelegate, session );
|
||||||
}
|
}
|
||||||
|
@ -143,10 +141,11 @@ public class PreparedStatementGroupStandard implements PreparedStatementGroup {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void release() {
|
public void release() {
|
||||||
statementMap.forEach( (tableName, statementDetails) -> statementDetails.releaseStatement( session ) );
|
statementMap.forEach( (tableName, statementDetails) -> {
|
||||||
|
release( statementDetails );
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static SortedMap<String, PreparedStatementDetails> createStatementDetailsMap(
|
private static SortedMap<String, PreparedStatementDetails> createStatementDetailsMap(
|
||||||
List<PreparableMutationOperation> jdbcMutations,
|
List<PreparableMutationOperation> jdbcMutations,
|
||||||
MutationType mutationType,
|
MutationType mutationType,
|
||||||
|
|
Loading…
Reference in New Issue