Skip to content

Commit 44084a1

Browse files
committed
HHH-19774 - Automatic flushing for child session with shared connection/tx
HHH-19808 - Automatic closing for child session with shared connection/tx
1 parent 6b98842 commit 44084a1

File tree

4 files changed

+57
-71
lines changed

4 files changed

+57
-71
lines changed

hibernate-core/src/main/java/org/hibernate/engine/creation/internal/ParentSessionObserver.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,6 @@ public interface ParentSessionObserver {
2222

2323
/**
2424
* Callback when the parent is closed. Used to close the child session.
25-
*
26-
* @apiNote Observation of closure of the parent is different from {@link org.hibernate.SessionBuilder#autoClose}
27-
* which indicates whether the session ought to be closed in response to transaction completion.
2825
*/
2926
void onParentClose();
3027
}

hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEventListener.java

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -24,38 +24,40 @@ public class DefaultFlushEventListener extends AbstractFlushingEventListener imp
2424
*/
2525
public void onFlush(FlushEvent event) throws HibernateException {
2626
final var source = event.getSession();
27-
final var persistenceContext = source.getPersistenceContextInternal();
27+
2828
final var eventMonitor = source.getEventMonitor();
29-
if ( persistenceContext.getNumberOfManagedEntities() > 0
30-
|| persistenceContext.getCollectionEntriesSize() > 0 ) {
31-
EVENT_LISTENER_LOGGER.executingFlush();
32-
final var flushEvent = eventMonitor.beginFlushEvent();
33-
final var eventListenerManager = source.getEventListenerManager();
34-
try {
35-
eventListenerManager.flushStart();
29+
final var flushEvent = eventMonitor.beginFlushEvent();
30+
31+
final var eventListenerManager = source.getEventListenerManager();
32+
eventListenerManager.flushStart();
33+
34+
try {
35+
final var persistenceContext = source.getPersistenceContextInternal();
36+
if ( persistenceContext.getNumberOfManagedEntities() > 0
37+
|| persistenceContext.getCollectionEntriesSize() > 0 ) {
38+
EVENT_LISTENER_LOGGER.executingFlush();
3639
flushEverythingToExecutions( event );
3740
performExecutions( source );
3841
postFlush( source );
39-
}
40-
finally {
41-
eventMonitor.completeFlushEvent( flushEvent, event );
42-
eventListenerManager.flushEnd(
43-
event.getNumberOfEntitiesProcessed(),
44-
event.getNumberOfCollectionsProcessed()
45-
);
46-
}
47-
48-
postPostFlush( source );
42+
postPostFlush( source );
4943

50-
final var statistics = source.getFactory().getStatistics();
51-
if ( statistics.isStatisticsEnabled() ) {
52-
statistics.flush();
44+
final var statistics = source.getFactory().getStatistics();
45+
if ( statistics.isStatisticsEnabled() ) {
46+
statistics.flush();
47+
}
48+
}
49+
else if ( source.getActionQueue().hasAnyQueuedActions() ) {
50+
EVENT_LISTENER_LOGGER.executingFlush();
51+
// execute any queued unloaded-entity deletions
52+
performExecutions( source );
5353
}
5454
}
55-
else if ( source.getActionQueue().hasAnyQueuedActions() ) {
56-
EVENT_LISTENER_LOGGER.executingFlush();
57-
// execute any queued unloaded-entity deletions
58-
performExecutions( source );
55+
finally {
56+
eventMonitor.completeFlushEvent( flushEvent, event );
57+
eventListenerManager.flushEnd(
58+
event.getNumberOfEntitiesProcessed(),
59+
event.getNumberOfCollectionsProcessed()
60+
);
5961
}
6062
}
6163
}

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -233,10 +233,7 @@ public void onParentFlush() {
233233

234234
@Override
235235
public void onParentClose() {
236-
// unless explicitly disabled, propagate the closure
237-
if ( sharedOptions.shouldAutoClose() ) {
238-
propagateClose();
239-
}
236+
propagateClose();
240237
}
241238
} );
242239
}

hibernate-core/src/test/java/org/hibernate/orm/test/sharedSession/SimpleSharedSessionBuildingTests.java

Lines changed: 29 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -184,79 +184,69 @@ void testClosePropagation(SessionFactoryScope factoryScope) {
184184
*/
185185
@Test
186186
void testAutoFlushStatefulChild(SessionFactoryScope factoryScope) {
187-
final var sqlCollector = factoryScope.getCollectingStatementInspector();
188-
sqlCollector.clear();
189-
190-
factoryScope.inTransaction( (parentSession) -> {
191-
try (SessionImplementor childSession = (SessionImplementor) parentSession
192-
.sessionWithOptions()
193-
.connection()
194-
.openSession()) {
195-
// persist an entity through the child session -
196-
// should be auto flushed (technically as part of the try-with-resources close of the child session)
197-
childSession.persist( new Something( 1, "first" ) );
198-
}
199-
} );
200-
201-
// make sure the flush and insert happened
202-
assertThat( sqlCollector.getSqlQueries() ).hasSize( 1 );
203-
factoryScope.inTransaction( (session) -> {
204-
final Something created = session.find( Something.class, 1 );
205-
assertThat( created ).isNotNull();
206-
} );
207-
208-
}
187+
final MutableObject<SharedSessionContractImplementor> parentSessionRef = new MutableObject<>();
188+
final MutableObject<SharedSessionContractImplementor> childSessionRef = new MutableObject<>();
209189

210-
/**
211-
* NOTE: builds on assertions from {@link #testConnectionAndTransactionSharing}
212-
* and {@linkplain #testClosePropagation}
213-
*/
214-
@Test
215-
void testAutoFlushStatefulChildNoClose(SessionFactoryScope factoryScope) {
216190
final var sqlCollector = factoryScope.getCollectingStatementInspector();
217191
sqlCollector.clear();
218192

219193
factoryScope.inTransaction( (parentSession) -> {
220-
SessionImplementor childSession = (SessionImplementor) parentSession
194+
parentSessionRef.set( parentSession );
195+
196+
// IMPORTANT: it is important that the child session not be closed here (e.g. try-with-resources).
197+
final SessionImplementor childSession = (SessionImplementor) parentSession
221198
.sessionWithOptions()
222199
.connection()
223200
.openSession();
201+
childSessionRef.set( childSession );
224202

225-
// persist an entity through the shared/child session.
226-
// then make sure the auto-flush of the parent session
227-
// propagates to the shared/child
203+
// persist an entity through the child session - should be auto flushed as part of the
204+
// parent session's flush cycle
228205
childSession.persist( new Something( 1, "first" ) );
229206
} );
230207

208+
assertThat( parentSessionRef.get().isClosed() ).isTrue();
209+
assertThat( childSessionRef.get().isClosed() ).isTrue();
210+
231211
// make sure the flush and insert happened
232212
assertThat( sqlCollector.getSqlQueries() ).hasSize( 1 );
233213
factoryScope.inTransaction( (session) -> {
234214
final Something created = session.find( Something.class, 1 );
235215
assertThat( created ).isNotNull();
236216
} );
237-
}
238217

218+
}
239219

240220

241221
/**
242222
* NOTE: builds on assertions from {@link #testConnectionAndTransactionSharing}
243223
*/
244224
@Test
245225
void testAutoFlushStatelessChild(SessionFactoryScope factoryScope) {
226+
final MutableObject<SharedSessionContractImplementor> parentSessionRef = new MutableObject<>();
227+
final MutableObject<SharedSessionContractImplementor> childSessionRef = new MutableObject<>();
228+
246229
final var sqlCollector = factoryScope.getCollectingStatementInspector();
247230
sqlCollector.clear();
248231

249232
factoryScope.inStatelessTransaction( (parentSession) -> {
250-
try (SessionImplementor childSession = (SessionImplementor) parentSession
233+
parentSessionRef.set( parentSession );
234+
235+
// IMPORTANT: it is important that the child session not be closed here (e.g. try-with-resources).
236+
final var childSession = (SessionImplementor) parentSession
251237
.sessionWithOptions()
252238
.connection()
253-
.openSession()) {
254-
// persist an entity through the child session -
255-
// should be auto flushed (technically as part of the try-with-resources close of the child session)
256-
childSession.persist( new Something( 1, "first" ) );
257-
}
239+
.openSession();
240+
childSessionRef.set( childSession );
241+
242+
// persist an entity through the child session - should be auto flushed as part of the
243+
// parent session's flush cycle
244+
childSession.persist( new Something( 1, "first" ) );
258245
} );
259246

247+
assertThat( parentSessionRef.get().isClosed() ).isTrue();
248+
assertThat( childSessionRef.get().isClosed() ).isTrue();
249+
260250
// make sure the flush and insert happened
261251
assertThat( sqlCollector.getSqlQueries() ).hasSize( 1 );
262252
factoryScope.inTransaction( (session) -> {

0 commit comments

Comments
 (0)