Skip to content

Commit

Permalink
HHH-18743 make batching explicit for StatelessSession
Browse files Browse the repository at this point in the history
1. ignore hibernate.jdbc.batch_size setting
2. add insertMultiple() and friends

Signed-off-by: Gavin King <[email protected]>
  • Loading branch information
gavinking committed Oct 22, 2024
1 parent dd8e186 commit f82c581
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,8 @@ public interface SharedSessionContract extends QueryProducer, AutoCloseable, Ser

/**
* Set the session-level JDBC batch size. Override the
* {@linkplain org.hibernate.boot.spi.SessionFactoryOptions#getJdbcBatchSize() factory-level}
* JDBC batch size controlled by the configuration property
* {@linkplain org.hibernate.boot.spi.SessionFactoryOptions#getJdbcBatchSize
* factory-level} JDBC batch size controlled by the configuration property
* {@value org.hibernate.cfg.AvailableSettings#STATEMENT_BATCH_SIZE}.
*
* @param jdbcBatchSize the new session-level JDBC batch size
Expand Down
52 changes: 52 additions & 0 deletions hibernate-core/src/main/java/org/hibernate/StatelessSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@
* <li>when an exception is thrown by a stateless session, the current
* transaction is not automatically marked for rollback.
* </ul>
* <p>
* Since version 7, the configuration property
* {@value org.hibernate.cfg.BatchSettings#STATEMENT_BATCH_SIZE} has no effect
* on a stateless session. Automatic batching may be enabled by explicitly
* {@linkplain #setJdbcBatchSize setting the batch size}. However, automatic
* batching has the side effect of delaying execution of the batched operation,
* thus undermining the synchronous nature of operations performed through a
* stateless session. A preferred approach is to explicitly batch operations via
* {@link #insertMultiple}, {@link #updateMultiple}, or {@link #deleteMultiple}.
*
* @author Gavin King
*/
Expand All @@ -85,6 +94,16 @@ public interface StatelessSession extends SharedSessionContract {
*/
Object insert(Object entity);

/**
* Insert multiple records.
*
* @param entities a list of transient instances to be inserted
*
* @since 7.0
*/
@Incubating
void insertMultiple(List<Object> entities);

/**
* Insert a record.
* <p>
Expand All @@ -108,6 +127,16 @@ public interface StatelessSession extends SharedSessionContract {
*/
void update(Object entity);

/**
* Update multiple records.
*
* @param entities a list of detached instances to be updated
*
* @since 7.0
*/
@Incubating
void updateMultiple(List<Object> entities);

/**
* Update a record.
* <p>
Expand All @@ -129,6 +158,16 @@ public interface StatelessSession extends SharedSessionContract {
*/
void delete(Object entity);

/**
* Delete multiple records.
*
* @param entities a list of detached instances to be deleted
*
* @since 7.0
*/
@Incubating
void deleteMultiple(List<Object> entities);

/**
* Delete a record.
* <p>
Expand Down Expand Up @@ -164,6 +203,19 @@ public interface StatelessSession extends SharedSessionContract {
@Incubating
void upsert(Object entity);

/**
* Perform an upsert, that is, to insert the record if it does
* not exist, or update the record if it already exists, for
* each given record.
*
* @param entities a list of detached instances and new
* instances with assigned identifiers
*
* @since 7.0
*/
@Incubating
void upsertMultiple(List<Object> entities);

/**
* Use a SQL {@code merge into} statement to perform an upsert.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1402,18 +1402,19 @@ public ExceptionConverter getExceptionConverter() {
return exceptionConverter;
}

@Override
public Integer getJdbcBatchSize() {
return jdbcBatchSize;
}

@Override
public EventManager getEventManager() {
return fastSessionServices.getEventManager();
public void setJdbcBatchSize(Integer jdbcBatchSize) {
this.jdbcBatchSize = jdbcBatchSize;
}

@Override
public void setJdbcBatchSize(Integer jdbcBatchSize) {
this.jdbcBatchSize = jdbcBatchSize;
public EventManager getEventManager() {
return fastSessionServices.getEventManager();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ public StatelessSessionImpl(SessionFactoryImpl factory, SessionCreationOptions o
temporaryPersistenceContext = new StatefulPersistenceContext( this );
influencers = new LoadQueryInfluencers( getFactory() );
setUpMultitenancy( factory, influencers );
setJdbcBatchSize( 0 );
}

@Override
Expand All @@ -119,6 +120,20 @@ public Object insert(Object entity) {
return insert( null, entity );
}

@Override
public void insertMultiple(List<Object> entities) {
final Integer batchSize = getJdbcBatchSize();
setJdbcBatchSize( entities.size() );
try {
for ( Object entity : entities ) {
insert( null, entity );
}
}
finally {
setJdbcBatchSize( batchSize );
}
}

@Override
public Object insert(String entityName, Object entity) {
checkOpen();
Expand Down Expand Up @@ -180,6 +195,20 @@ public void delete(Object entity) {
delete( null, entity );
}

@Override
public void deleteMultiple(List<Object> entities) {
final Integer batchSize = getJdbcBatchSize();
setJdbcBatchSize( entities.size() );
try {
for ( Object entity : entities ) {
delete( null, entity );
}
}
finally {
setJdbcBatchSize( batchSize );
}
}

@Override
public void delete(String entityName, Object entity) {
checkOpen();
Expand Down Expand Up @@ -215,8 +244,17 @@ public void update(Object entity) {
}

@Override
public void upsert(Object entity) {
upsert( null, entity );
public void updateMultiple(List<Object> entities) {
final Integer batchSize = getJdbcBatchSize();
setJdbcBatchSize( entities.size() );
try {
for ( Object entity : entities ) {
update( null, entity );
}
}
finally {
setJdbcBatchSize( batchSize );
}
}

@Override
Expand Down Expand Up @@ -257,6 +295,25 @@ public void update(String entityName, Object entity) {
}
}

@Override
public void upsert(Object entity) {
upsert( null, entity );
}

@Override
public void upsertMultiple(List<Object> entities) {
final Integer batchSize = getJdbcBatchSize();
setJdbcBatchSize( entities.size() );
try {
for ( Object entity : entities ) {
upsert( null, entity );
}
}
finally {
setJdbcBatchSize( batchSize );
}
}

@Override
public void upsert(String entityName, Object entity) {
checkOpen();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
/**
* Contract for something that controls a {@link JdbcSessionContext}.
* <p>
* The term "JDBC session" is taken from the SQL specification which
* The term <em>JDBC session</em> is taken from the SQL specification which
* calls a connection and its associated transaction context a "session".
*
* @apiNote The name comes from the design idea of a {@code JdbcSession}
Expand All @@ -28,9 +28,9 @@ public interface JdbcSessionOwner {
JdbcConnectionAccess getJdbcConnectionAccess();

/**
* Obtain the builder for TransactionCoordinator instances
* Obtain the {@link TransactionCoordinator}.
*
* @return The TransactionCoordinatorBuilder
* @return The {@code TransactionCoordinator}
*/
TransactionCoordinator getTransactionCoordinator();

Expand All @@ -43,7 +43,7 @@ public interface JdbcSessionOwner {
void startTransactionBoundary();

/**
* A after-begin callback from the coordinator to its owner.
* An after-begin callback from the coordinator to its owner.
*/
void afterTransactionBegin();

Expand All @@ -63,8 +63,8 @@ public interface JdbcSessionOwner {
void flushBeforeTransactionCompletion();

/**
* Get the Session-level JDBC batch size.
* @return Session-level JDBC batch size
* Get the session-level JDBC batch size.
* @return session-level JDBC batch size
*
* @since 5.2
*/
Expand Down
8 changes: 8 additions & 0 deletions migration-guide.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,14 @@ must be explicitly set to true.

The signature of the `Configurable#configure` method changed from accepting just a `ServiceRegistry` instance to the new `GeneratorCreationContext` interface, which exposes a lot more useful information when configuring the generator itself. The old signature has been deprecated for removal, so you should migrate any custom `Configurable` generator implementation to the new one.

[[stateless-session-jdbc-batching]]
== JDBC batching with `StatelessSession`

Automatic JDBC batching has the side effect of delaying the execution of the batched operation, and this undermines the synchronous nature of operations performed through a stateless session.
In Hibernate 7, the configuration property `hibernate.jdbc.batch_size` now has no effect on a stateless session.
Automatic batching may be enabled by explicitly calling `setJdbcBatchSize()`.
However, the preferred approach is to explicitly batch operations via `insertMultiple()`, `updateMultiple()`, or `deleteMultiple()`.

[[hbm-transform]]
== hbm.xml Transformation

Expand Down

0 comments on commit f82c581

Please sign in to comment.