HHH-16386 - Disable batching for dynamic-insert and dynamic-update
Signed-off-by: Jan Schatteman <jschatte@redhat.com>
This commit is contained in:
parent
fff7f341b1
commit
a26b19d93d
|
@ -152,7 +152,7 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
|
|||
|
||||
final TableInclusionChecker tableInclusionChecker = getTableInclusionChecker( insertValuesAnalysis );
|
||||
|
||||
final MutationExecutor mutationExecutor = executor( session, staticInsertGroup );
|
||||
final MutationExecutor mutationExecutor = executor( session, staticInsertGroup, false );
|
||||
|
||||
decomposeForInsert(
|
||||
mutationExecutor,
|
||||
|
@ -271,7 +271,7 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
|
|||
final boolean[] insertability = getPropertiesToInsert( values );
|
||||
final MutationOperationGroup insertGroup = generateDynamicInsertSqlGroup( insertability );
|
||||
|
||||
final MutationExecutor mutationExecutor = executor( session, insertGroup );
|
||||
final MutationExecutor mutationExecutor = executor( session, insertGroup, true );
|
||||
|
||||
final InsertValuesAnalysis insertValuesAnalysis = new InsertValuesAnalysis( entityPersister(), values );
|
||||
|
||||
|
@ -301,11 +301,11 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
|
|||
}
|
||||
}
|
||||
|
||||
private MutationExecutor executor(SharedSessionContractImplementor session, MutationOperationGroup group) {
|
||||
private MutationExecutor executor(SharedSessionContractImplementor session, MutationOperationGroup group, boolean dynamicUpdate) {
|
||||
return session.getFactory()
|
||||
.getServiceRegistry()
|
||||
.getService( MutationExecutorService.class )
|
||||
.createExecutor( ( session.getTransactionCoordinator() != null &&
|
||||
.createExecutor( ( !dynamicUpdate && session.getTransactionCoordinator() != null &&
|
||||
session.getTransactionCoordinator().isTransactionActive() ? () -> batchKey : () -> null ),
|
||||
group, session );
|
||||
}
|
||||
|
|
|
@ -447,7 +447,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
|||
|
||||
final EntityTableMapping mutatingTableDetails = (EntityTableMapping) versionUpdateGroup.getSingleOperation().getTableDetails();
|
||||
|
||||
final MutationExecutor mutationExecutor = executor( session, versionUpdateGroup );
|
||||
final MutationExecutor mutationExecutor = executor( session, versionUpdateGroup, false );
|
||||
|
||||
final EntityVersionMapping versionMapping = entityPersister().getVersionMapping();
|
||||
|
||||
|
@ -703,7 +703,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
|||
UpdateValuesAnalysisImpl valuesAnalysis,
|
||||
SharedSessionContractImplementor session) {
|
||||
|
||||
final MutationExecutor mutationExecutor = executor( session, staticUpdateGroup );
|
||||
final MutationExecutor mutationExecutor = executor( session, staticUpdateGroup, false );
|
||||
|
||||
decomposeForUpdate(
|
||||
id,
|
||||
|
@ -921,7 +921,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
|||
|
||||
// and then execute them
|
||||
|
||||
final MutationExecutor mutationExecutor = executor( session, dynamicUpdateGroup );
|
||||
final MutationExecutor mutationExecutor = executor( session, dynamicUpdateGroup, true );
|
||||
|
||||
decomposeForUpdate(
|
||||
id,
|
||||
|
@ -966,11 +966,11 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
|||
}
|
||||
}
|
||||
|
||||
private MutationExecutor executor(SharedSessionContractImplementor session, MutationOperationGroup group) {
|
||||
private MutationExecutor executor(SharedSessionContractImplementor session, MutationOperationGroup group, boolean dynamicUpdate) {
|
||||
return session.getSessionFactory()
|
||||
.getServiceRegistry()
|
||||
.getService( MutationExecutorService.class )
|
||||
.createExecutor( ( session.getTransactionCoordinator() != null &&
|
||||
.createExecutor( ( !dynamicUpdate && session.getTransactionCoordinator() != null &&
|
||||
session.getTransactionCoordinator().isTransactionActive() ? () -> batchKey : () -> null ),
|
||||
group, session );
|
||||
}
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
package org.hibernate.orm.test.batch;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.annotations.DynamicInsert;
|
||||
import org.hibernate.annotations.DynamicUpdate;
|
||||
|
||||
import org.hibernate.testing.jdbc.SQLStatementInspector;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.FailureExpected;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Basic;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Inheritance;
|
||||
import jakarta.persistence.PrimaryKeyJoinColumn;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import static jakarta.persistence.InheritanceType.JOINED;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hibernate.cfg.AvailableSettings.STATEMENT_BATCH_SIZE;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class BatchedMultiTableDynamicStatementTests {
|
||||
|
||||
@Test
|
||||
@ServiceRegistry( settings = @Setting( name = STATEMENT_BATCH_SIZE, value = "2" ) )
|
||||
@DomainModel( annotatedClasses = { Payment.class, CheckPayment.class } )
|
||||
@SessionFactory( useCollectingStatementInspector = true )
|
||||
public void testBatched(SessionFactoryScope scope) {
|
||||
final SQLStatementInspector statementCollector = scope.getCollectingStatementInspector();
|
||||
statementCollector.clear();
|
||||
|
||||
createData( scope );
|
||||
|
||||
assertThat( statementCollector.getSqlQueries() ).hasSize( 6 );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final List<Payment> payments = session.createSelectionQuery( "from Payment", Payment.class ).list();
|
||||
assertThat( payments ).hasSize( 3 );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@ServiceRegistry( settings = @Setting( name = STATEMENT_BATCH_SIZE, value = "-1" ) )
|
||||
@DomainModel( annotatedClasses = { Payment.class, CheckPayment.class } )
|
||||
@SessionFactory( useCollectingStatementInspector = true )
|
||||
public void testNonBatched(SessionFactoryScope scope) {
|
||||
final SQLStatementInspector statementCollector = scope.getCollectingStatementInspector();
|
||||
statementCollector.clear();
|
||||
|
||||
createData( scope );
|
||||
|
||||
assertThat( statementCollector.getSqlQueries() ).hasSize( 6 );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final List<Payment> payments = session.createSelectionQuery( "from Payment", Payment.class ).list();
|
||||
assertThat( payments ).hasSize( 3 );
|
||||
} );
|
||||
}
|
||||
|
||||
private static void createData(SessionFactoryScope scope) {
|
||||
final CheckPayment payment = new CheckPayment();
|
||||
payment.setId( 1 );
|
||||
payment.setAmount( 123.00 );
|
||||
payment.setRoute( "0123-45-6789" );
|
||||
payment.setAccount( "0089654321" );
|
||||
|
||||
final CheckPayment payment2 = new CheckPayment();
|
||||
payment2.setId( 2 );
|
||||
payment2.setAmount( 230.00 );
|
||||
payment2.setRoute( "0123-45-6789" );
|
||||
payment2.setAccount( "0089654321" );
|
||||
payment2.setMemo( "Car Loan" );
|
||||
|
||||
final CheckPayment payment3 = new CheckPayment();
|
||||
payment3.setId( 3 );
|
||||
payment3.setAmount( 1234.00 );
|
||||
payment3.setRoute( "0123-45-6789" );
|
||||
payment3.setAccount( "0089654321" );
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
session.persist( payment );
|
||||
session.persist( payment2 );
|
||||
session.persist( payment3 );
|
||||
} );
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void dropTestData(SessionFactoryScope scope) {
|
||||
scope.inTransaction( (session) -> {
|
||||
session.createMutationQuery( "delete Payment" ).executeUpdate();
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity( name = "Payment" )
|
||||
@Table( name = "payments" )
|
||||
@Inheritance( strategy = JOINED )
|
||||
@DynamicInsert @DynamicUpdate
|
||||
public static class Payment {
|
||||
@Id
|
||||
private Integer id;
|
||||
private double amount;
|
||||
private String comment;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public double getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(double amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
public void setComment(String comment) {
|
||||
this.comment = comment;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "CheckPayment")
|
||||
@Table( name = "check_payments" )
|
||||
@PrimaryKeyJoinColumn( name = "payment_fk" )
|
||||
@DynamicInsert
|
||||
@DynamicUpdate
|
||||
public static class CheckPayment extends Payment {
|
||||
@Basic(optional = false)
|
||||
private String route;
|
||||
@Basic(optional = false)
|
||||
private String account;
|
||||
private String memo;
|
||||
|
||||
public String getRoute() {
|
||||
return route;
|
||||
}
|
||||
|
||||
public void setRoute(String route) {
|
||||
this.route = route;
|
||||
}
|
||||
|
||||
public String getAccount() {
|
||||
return account;
|
||||
}
|
||||
|
||||
public void setAccount(String account) {
|
||||
this.account = account;
|
||||
}
|
||||
|
||||
public String getMemo() {
|
||||
return memo;
|
||||
}
|
||||
|
||||
public void setMemo(String memo) {
|
||||
this.memo = memo;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* 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
|
||||
*/
|
||||
package org.hibernate.orm.test.batch;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.annotations.DynamicInsert;
|
||||
import org.hibernate.annotations.DynamicUpdate;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.query.Query;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
/**
|
||||
* @author Jan Schatteman
|
||||
*/
|
||||
@ServiceRegistry(
|
||||
settings = {
|
||||
@Setting(name = AvailableSettings.STATEMENT_BATCH_SIZE, value = "2"),
|
||||
}
|
||||
)
|
||||
@DomainModel(
|
||||
annotatedClasses = { DynamicMutationsAndBatchingTest.EntityA.class }
|
||||
)
|
||||
@SessionFactory
|
||||
@TestForIssue( jiraKey = "HHH-16352")
|
||||
public class DynamicMutationsAndBatchingTest {
|
||||
|
||||
@AfterEach
|
||||
public void cleanup( SessionFactoryScope scope ) {
|
||||
scope.inTransaction(
|
||||
s -> {
|
||||
s.createMutationQuery( "delete from EntityA" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDynamicInserts( SessionFactoryScope scope ) {
|
||||
scope.inTransaction(
|
||||
s -> {
|
||||
EntityA entityA1 = new EntityA(1);
|
||||
entityA1.propertyA = 1;
|
||||
|
||||
EntityA entityA2 = new EntityA(2);
|
||||
entityA2.propertyB = 2;
|
||||
entityA2.propertyC = 3;
|
||||
|
||||
EntityA entityA3 = new EntityA(3);
|
||||
entityA3.propertyA = 4;
|
||||
entityA3.propertyC = 5;
|
||||
|
||||
s.persist(entityA1);
|
||||
s.persist(entityA2);
|
||||
s.persist(entityA3);
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
s -> {
|
||||
Query<EntityA> query = s.createQuery( "select e from EntityA e where id = :id", EntityA.class);
|
||||
EntityA a1 = query.setParameter( "id", 1 ).uniqueResult();
|
||||
assertNotNull( a1 );
|
||||
assertNull(a1.propertyB);
|
||||
assertNull(a1.propertyC);
|
||||
assertEquals( 1, a1.propertyA );
|
||||
|
||||
EntityA a2 = query.setParameter( "id", 2 ).uniqueResult();
|
||||
assertNotNull( a2 );
|
||||
assertNull( a2.propertyA );
|
||||
assertEquals( 2, a2.propertyB );
|
||||
assertEquals( 3, a2.propertyC );
|
||||
|
||||
EntityA a3 = query.setParameter( "id", 3 ).uniqueResult();
|
||||
assertNotNull( a3 );
|
||||
assertNull( a3.propertyB );
|
||||
assertEquals( 4, a3.propertyA );
|
||||
assertEquals( 5, a3.propertyC );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDynamicUpdates( SessionFactoryScope scope ) {
|
||||
scope.inTransaction(
|
||||
s -> {
|
||||
EntityA entityA1 = new EntityA(1);
|
||||
EntityA entityA2 = new EntityA(2);
|
||||
EntityA entityA3 = new EntityA(3);
|
||||
s.persist(entityA1);
|
||||
s.persist(entityA2);
|
||||
s.persist(entityA3);
|
||||
}
|
||||
);
|
||||
|
||||
scope.inSession(
|
||||
s -> {
|
||||
Query<EntityA> query = s.createQuery( "select e from EntityA e order by id asc", EntityA.class);
|
||||
Transaction tx = s.beginTransaction();
|
||||
List<EntityA> actual = query.list();
|
||||
actual.get(0).propertyA = 1;
|
||||
actual.get(1).propertyA = 2;
|
||||
actual.get(1).propertyB = 2;
|
||||
actual.get(2).propertyA = 4;
|
||||
s.flush();
|
||||
tx.commit();
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
s -> {
|
||||
Query<EntityA> query = s.createQuery( "select e from EntityA e where id = :id", EntityA.class);
|
||||
EntityA a1 = query.setParameter( "id", 1 ).uniqueResult();
|
||||
assertNotNull( a1 );
|
||||
assertEquals( 1, a1.propertyA );
|
||||
assertNull(a1.propertyB);
|
||||
assertNull(a1.propertyC);
|
||||
|
||||
EntityA a2 = query.setParameter( "id", 2 ).uniqueResult();
|
||||
assertNotNull( a2 );
|
||||
assertNull( a2.propertyC );
|
||||
assertEquals( 2, a2.propertyA );
|
||||
assertEquals( 2, a2.propertyB );
|
||||
|
||||
EntityA a3 = query.setParameter( "id", 3 ).uniqueResult();
|
||||
assertNotNull( a3 );
|
||||
assertNull( a3.propertyB );
|
||||
assertNull( a3.propertyC );
|
||||
assertEquals( 4, a3.propertyA );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@DynamicInsert
|
||||
@DynamicUpdate
|
||||
@Entity(name="EntityA")
|
||||
@Table(name = "ENTITY_A")
|
||||
public static class EntityA {
|
||||
|
||||
@Id
|
||||
@Column(name = "ID")
|
||||
Integer id;
|
||||
|
||||
@Column(name = "PROPERTY_A")
|
||||
Integer propertyA;
|
||||
|
||||
@Column(name = "PROPERTY_B")
|
||||
Integer propertyB;
|
||||
|
||||
@Column(name = "PROPERTY_C")
|
||||
Integer propertyC;
|
||||
|
||||
public EntityA() {
|
||||
}
|
||||
|
||||
public EntityA(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue