Skip to content

Commit f82c581

Browse files
committed
HHH-18743 make batching explicit for StatelessSession
1. ignore hibernate.jdbc.batch_size setting 2. add insertMultiple() and friends Signed-off-by: Gavin King <[email protected]>
1 parent dd8e186 commit f82c581

File tree

6 files changed

+132
-14
lines changed

6 files changed

+132
-14
lines changed

hibernate-core/src/main/java/org/hibernate/SharedSessionContract.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,8 +203,8 @@ public interface SharedSessionContract extends QueryProducer, AutoCloseable, Ser
203203

204204
/**
205205
* Set the session-level JDBC batch size. Override the
206-
* {@linkplain org.hibernate.boot.spi.SessionFactoryOptions#getJdbcBatchSize() factory-level}
207-
* JDBC batch size controlled by the configuration property
206+
* {@linkplain org.hibernate.boot.spi.SessionFactoryOptions#getJdbcBatchSize
207+
* factory-level} JDBC batch size controlled by the configuration property
208208
* {@value org.hibernate.cfg.AvailableSettings#STATEMENT_BATCH_SIZE}.
209209
*
210210
* @param jdbcBatchSize the new session-level JDBC batch size

hibernate-core/src/main/java/org/hibernate/StatelessSession.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,15 @@
6060
* <li>when an exception is thrown by a stateless session, the current
6161
* transaction is not automatically marked for rollback.
6262
* </ul>
63+
* <p>
64+
* Since version 7, the configuration property
65+
* {@value org.hibernate.cfg.BatchSettings#STATEMENT_BATCH_SIZE} has no effect
66+
* on a stateless session. Automatic batching may be enabled by explicitly
67+
* {@linkplain #setJdbcBatchSize setting the batch size}. However, automatic
68+
* batching has the side effect of delaying execution of the batched operation,
69+
* thus undermining the synchronous nature of operations performed through a
70+
* stateless session. A preferred approach is to explicitly batch operations via
71+
* {@link #insertMultiple}, {@link #updateMultiple}, or {@link #deleteMultiple}.
6372
*
6473
* @author Gavin King
6574
*/
@@ -85,6 +94,16 @@ public interface StatelessSession extends SharedSessionContract {
8594
*/
8695
Object insert(Object entity);
8796

97+
/**
98+
* Insert multiple records.
99+
*
100+
* @param entities a list of transient instances to be inserted
101+
*
102+
* @since 7.0
103+
*/
104+
@Incubating
105+
void insertMultiple(List<Object> entities);
106+
88107
/**
89108
* Insert a record.
90109
* <p>
@@ -108,6 +127,16 @@ public interface StatelessSession extends SharedSessionContract {
108127
*/
109128
void update(Object entity);
110129

130+
/**
131+
* Update multiple records.
132+
*
133+
* @param entities a list of detached instances to be updated
134+
*
135+
* @since 7.0
136+
*/
137+
@Incubating
138+
void updateMultiple(List<Object> entities);
139+
111140
/**
112141
* Update a record.
113142
* <p>
@@ -129,6 +158,16 @@ public interface StatelessSession extends SharedSessionContract {
129158
*/
130159
void delete(Object entity);
131160

161+
/**
162+
* Delete multiple records.
163+
*
164+
* @param entities a list of detached instances to be deleted
165+
*
166+
* @since 7.0
167+
*/
168+
@Incubating
169+
void deleteMultiple(List<Object> entities);
170+
132171
/**
133172
* Delete a record.
134173
* <p>
@@ -164,6 +203,19 @@ public interface StatelessSession extends SharedSessionContract {
164203
@Incubating
165204
void upsert(Object entity);
166205

206+
/**
207+
* Perform an upsert, that is, to insert the record if it does
208+
* not exist, or update the record if it already exists, for
209+
* each given record.
210+
*
211+
* @param entities a list of detached instances and new
212+
* instances with assigned identifiers
213+
*
214+
* @since 7.0
215+
*/
216+
@Incubating
217+
void upsertMultiple(List<Object> entities);
218+
167219
/**
168220
* Use a SQL {@code merge into} statement to perform an upsert.
169221
*

hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,18 +1402,19 @@ public ExceptionConverter getExceptionConverter() {
14021402
return exceptionConverter;
14031403
}
14041404

1405+
@Override
14051406
public Integer getJdbcBatchSize() {
14061407
return jdbcBatchSize;
14071408
}
14081409

14091410
@Override
1410-
public EventManager getEventManager() {
1411-
return fastSessionServices.getEventManager();
1411+
public void setJdbcBatchSize(Integer jdbcBatchSize) {
1412+
this.jdbcBatchSize = jdbcBatchSize;
14121413
}
14131414

14141415
@Override
1415-
public void setJdbcBatchSize(Integer jdbcBatchSize) {
1416-
this.jdbcBatchSize = jdbcBatchSize;
1416+
public EventManager getEventManager() {
1417+
return fastSessionServices.getEventManager();
14171418
}
14181419

14191420
@Override

hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ public StatelessSessionImpl(SessionFactoryImpl factory, SessionCreationOptions o
105105
temporaryPersistenceContext = new StatefulPersistenceContext( this );
106106
influencers = new LoadQueryInfluencers( getFactory() );
107107
setUpMultitenancy( factory, influencers );
108+
setJdbcBatchSize( 0 );
108109
}
109110

110111
@Override
@@ -119,6 +120,20 @@ public Object insert(Object entity) {
119120
return insert( null, entity );
120121
}
121122

123+
@Override
124+
public void insertMultiple(List<Object> entities) {
125+
final Integer batchSize = getJdbcBatchSize();
126+
setJdbcBatchSize( entities.size() );
127+
try {
128+
for ( Object entity : entities ) {
129+
insert( null, entity );
130+
}
131+
}
132+
finally {
133+
setJdbcBatchSize( batchSize );
134+
}
135+
}
136+
122137
@Override
123138
public Object insert(String entityName, Object entity) {
124139
checkOpen();
@@ -180,6 +195,20 @@ public void delete(Object entity) {
180195
delete( null, entity );
181196
}
182197

198+
@Override
199+
public void deleteMultiple(List<Object> entities) {
200+
final Integer batchSize = getJdbcBatchSize();
201+
setJdbcBatchSize( entities.size() );
202+
try {
203+
for ( Object entity : entities ) {
204+
delete( null, entity );
205+
}
206+
}
207+
finally {
208+
setJdbcBatchSize( batchSize );
209+
}
210+
}
211+
183212
@Override
184213
public void delete(String entityName, Object entity) {
185214
checkOpen();
@@ -215,8 +244,17 @@ public void update(Object entity) {
215244
}
216245

217246
@Override
218-
public void upsert(Object entity) {
219-
upsert( null, entity );
247+
public void updateMultiple(List<Object> entities) {
248+
final Integer batchSize = getJdbcBatchSize();
249+
setJdbcBatchSize( entities.size() );
250+
try {
251+
for ( Object entity : entities ) {
252+
update( null, entity );
253+
}
254+
}
255+
finally {
256+
setJdbcBatchSize( batchSize );
257+
}
220258
}
221259

222260
@Override
@@ -257,6 +295,25 @@ public void update(String entityName, Object entity) {
257295
}
258296
}
259297

298+
@Override
299+
public void upsert(Object entity) {
300+
upsert( null, entity );
301+
}
302+
303+
@Override
304+
public void upsertMultiple(List<Object> entities) {
305+
final Integer batchSize = getJdbcBatchSize();
306+
setJdbcBatchSize( entities.size() );
307+
try {
308+
for ( Object entity : entities ) {
309+
upsert( null, entity );
310+
}
311+
}
312+
finally {
313+
setJdbcBatchSize( batchSize );
314+
}
315+
}
316+
260317
@Override
261318
public void upsert(String entityName, Object entity) {
262319
checkOpen();

hibernate-core/src/main/java/org/hibernate/resource/jdbc/spi/JdbcSessionOwner.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
/**
1313
* Contract for something that controls a {@link JdbcSessionContext}.
1414
* <p>
15-
* The term "JDBC session" is taken from the SQL specification which
15+
* The term <em>JDBC session</em> is taken from the SQL specification which
1616
* calls a connection and its associated transaction context a "session".
1717
*
1818
* @apiNote The name comes from the design idea of a {@code JdbcSession}
@@ -28,9 +28,9 @@ public interface JdbcSessionOwner {
2828
JdbcConnectionAccess getJdbcConnectionAccess();
2929

3030
/**
31-
* Obtain the builder for TransactionCoordinator instances
31+
* Obtain the {@link TransactionCoordinator}.
3232
*
33-
* @return The TransactionCoordinatorBuilder
33+
* @return The {@code TransactionCoordinator}
3434
*/
3535
TransactionCoordinator getTransactionCoordinator();
3636

@@ -43,7 +43,7 @@ public interface JdbcSessionOwner {
4343
void startTransactionBoundary();
4444

4545
/**
46-
* A after-begin callback from the coordinator to its owner.
46+
* An after-begin callback from the coordinator to its owner.
4747
*/
4848
void afterTransactionBegin();
4949

@@ -63,8 +63,8 @@ public interface JdbcSessionOwner {
6363
void flushBeforeTransactionCompletion();
6464

6565
/**
66-
* Get the Session-level JDBC batch size.
67-
* @return Session-level JDBC batch size
66+
* Get the session-level JDBC batch size.
67+
* @return session-level JDBC batch size
6868
*
6969
* @since 5.2
7070
*/

migration-guide.adoc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,14 @@ must be explicitly set to true.
340340

341341
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.
342342

343+
[[stateless-session-jdbc-batching]]
344+
== JDBC batching with `StatelessSession`
345+
346+
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.
347+
In Hibernate 7, the configuration property `hibernate.jdbc.batch_size` now has no effect on a stateless session.
348+
Automatic batching may be enabled by explicitly calling `setJdbcBatchSize()`.
349+
However, the preferred approach is to explicitly batch operations via `insertMultiple()`, `updateMultiple()`, or `deleteMultiple()`.
350+
343351
[[hbm-transform]]
344352
== hbm.xml Transformation
345353

0 commit comments

Comments
 (0)