Skip to content

Commit eddc9b9

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 abc7348 commit eddc9b9

File tree

6 files changed

+115
-49
lines changed

6 files changed

+115
-49
lines changed

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

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -147,17 +147,7 @@ public TransactionCompletionCallbacksImplementor getTransactionCompletionCallbac
147147
}
148148

149149
@Override
150-
public void registerParentSessionObserver(ParentSessionObserver callbacks) {
151-
originalSession.getEventListenerManager().addListener( new SessionEventListener() {
152-
@Override
153-
public void flushStart() {
154-
callbacks.onParentFlush();
155-
}
156-
157-
@Override
158-
public void end() {
159-
callbacks.onParentClose();
160-
}
161-
} );
150+
public void registerParentSessionObserver(ParentSessionObserver observer) {
151+
registerParentSessionObserver( observer, originalSession );
162152
}
163153
}

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

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -260,20 +260,9 @@ public SharedSessionBuilderImplementor subselectFetchEnabled(boolean subselectFe
260260
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
261261
// SharedSessionCreationOptions
262262

263-
264263
@Override
265-
public void registerParentSessionObserver(ParentSessionObserver callbacks) {
266-
original.getEventListenerManager().addListener( new SessionEventListener() {
267-
@Override
268-
public void flushEnd(int numberOfEntities, int numberOfCollections) {
269-
callbacks.onParentFlush();
270-
}
271-
272-
@Override
273-
public void end() {
274-
callbacks.onParentClose();
275-
}
276-
} );
264+
public void registerParentSessionObserver(ParentSessionObserver observer) {
265+
registerParentSessionObserver( observer, original );
277266
}
278267

279268
@Override

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
*/
55
package org.hibernate.engine.creation.internal;
66

7+
import org.hibernate.SessionEventListener;
78
import org.hibernate.Transaction;
89
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
10+
import org.hibernate.engine.spi.SharedSessionContractImplementor;
911
import org.hibernate.engine.spi.TransactionCompletionCallbacksImplementor;
1012
import org.hibernate.resource.transaction.spi.TransactionCoordinator;
1113

@@ -30,6 +32,28 @@ public interface SharedSessionCreationOptions extends SessionCreationOptions {
3032
/**
3133
* Registers callbacks for the child session to integrate with events of the parent session.
3234
*/
33-
void registerParentSessionObserver(ParentSessionObserver callbacks);
35+
void registerParentSessionObserver(ParentSessionObserver observer);
36+
37+
/**
38+
* Consolidated implementation of adding the parent session observer.
39+
*/
40+
default void registerParentSessionObserver(ParentSessionObserver observer, SharedSessionContractImplementor original) {
41+
original.getEventListenerManager().addListener( new SessionEventListener() {
42+
@Override
43+
public void flushEnd(int numberOfEntities, int numberOfCollections) {
44+
observer.onParentFlush();
45+
}
46+
47+
@Override
48+
public void partialFlushEnd(int numberOfEntities, int numberOfCollections) {
49+
observer.onParentFlush();
50+
}
51+
52+
@Override
53+
public void end() {
54+
observer.onParentClose();
55+
}
56+
} );
57+
}
3458

3559
}

hibernate-jfr/src/test/java/org/hibernate/event/jfr/flush/FlushTests.java

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import static org.assertj.core.api.Assertions.assertThat;
2525

26+
@SuppressWarnings("JUnitMalformedDeclaration")
2627
@JfrEventTest
2728
@DomainModel(annotatedClasses = {
2829
FlushTests.TestEntity.class,
@@ -67,22 +68,21 @@ public void testFlushEvent(SessionFactoryScope scope) {
6768

6869
@Test
6970
@EnableEvent(JdbcBatchExecutionEvent.NAME)
70-
public void testFlushNoFired(SessionFactoryScope scope) {
71+
public void testFlushNotFired(SessionFactoryScope scope) {
7172
jfrEvents.reset();
72-
scope.inTransaction(
73-
session -> {
74-
75-
}
76-
);
77-
List<RecordedEvent> events = jfrEvents.events()
78-
.filter(
79-
recordedEvent ->
80-
{
81-
String eventName = recordedEvent.getEventType().getName();
82-
return eventName.equals( FlushEvent.NAME );
83-
}
84-
).toList();
85-
assertThat( events ).hasSize( 0 );
73+
scope.inTransaction( (session) -> {
74+
// do nothing
75+
} );
76+
List<RecordedEvent> events = jfrEvents.events().filter( (recordedEvent) -> {
77+
String eventName = recordedEvent.getEventType().getName();
78+
return eventName.equals( FlushEvent.NAME );
79+
} ).toList();
80+
81+
// the flush event should be triggered by the commit
82+
assertThat( events ).hasSize( 1 );
83+
// however, it should not affect anything
84+
assertThat( events.get( 0 ).getInt( "numberOfEntitiesProcessed" ) ).isEqualTo( 0 );
85+
assertThat( events.get( 0 ).getInt( "numberOfCollectionsProcessed" ) ).isEqualTo( 0 );
8686
}
8787

8888
@Entity(name = "TestEntity")

migration-guide.adoc

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,6 @@ See the link:{releaseSeriesBase}#whats-new[website] for the list of new features
4040

4141
This section describes changes to contracts (classes, interfaces, methods, etc.) which are considered https://hibernate.org/community/compatibility-policy/#api[API].
4242

43-
* Code underlying the session builder APIs was reengineered, and the behavior of `noInterceptor()` for `SharedSessionBuilder` and `SharedStatelessSessionBuilder` was aligned with the preexisting semantics of this method on `SessionBuilder` and `StatelessSessionBuilder`.
44-
The previous behavior may be recovered by calling `noSessionInterceptorCreation()`.
45-
46-
* `org.hibernate.dialect.AzureSQLServerDialect` was deprecated. Use `org.hibernate.dialect.SQLServerDialect` instead.
47-
If you set `hibernate.boot.allow_jdbc_metadata_access=false` for offline startup,
48-
remember to also set the targeted database version through `jakarta.persistence.database-product-version`;
49-
this would be 16.0 for SQL Server 2022 or 17.0 for SQL Server 2025.
5043

5144
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5245
// SPI changes
@@ -57,7 +50,58 @@ This section describes changes to contracts (classes, interfaces, methods, etc.)
5750

5851
This section describes changes to contracts (classes, interfaces, methods, etc.) which are considered https://hibernate.org/community/compatibility-policy/#spi[SPI].
5952

60-
* Some operations of `TypeConfiguration`, `JavaTypeRegistry`, and `BasicTypeRegistry` used unbound type parameters in the return type. The generic signatures of these methods have been changed for improved type safety.
53+
[[registry-generic-signatures]]
54+
=== Registry Generic Signatures
55+
56+
Some operations of `TypeConfiguration`, `JavaTypeRegistry`, and `BasicTypeRegistry` had previously used unbound type parameters in the return type. The generic signatures of these methods have been changed for improved type safety.
57+
58+
59+
[[AzureSQLServerDialect]]
60+
=== AzureSQLServerDialect Deprecation
61+
62+
`org.hibernate.dialect.AzureSQLServerDialect` was deprecated; use `org.hibernate.dialect.SQLServerDialect` instead.
63+
64+
[IMPORTANT]
65+
====
66+
If you set `hibernate.boot.allow_jdbc_metadata_access=false` for offline startup,
67+
remember to also set the targeted database version through `jakarta.persistence.database-product-version` - this would be 16.0 for SQL Server 2022 or 17.0 for SQL Server 2025.
68+
====
69+
70+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
71+
// Changes in Behavior
72+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
73+
74+
[[behavior-changes]]
75+
== Changes in Behavior
76+
77+
[[child-session-flush-close]]
78+
=== Child Session Flush/Close Behavior
79+
80+
`Session` and `StatelessSession` which share transactional context with a parent now have slightly different semantics in regard to flushing and closing -
81+
82+
* when the parent is flushed, the child is flushed
83+
* when the parent is closed, the child is closed
84+
85+
[NOTE]
86+
====
87+
This led to a change in triggering of flush events for both -
88+
89+
* `SessionEventListener` registrations
90+
* JFR events
91+
92+
In both cases, the events are now triggered regardless of whether any entities or collections were actually flushed.
93+
Each already carried the number of entities and the number of collections which were actually flushed.
94+
Previously, when no entities and no collections were flushed to the database no event was generated; the event is now generated and both values will be zero.
95+
96+
Interestingly, this now also aligns with handling for auto-flush events which already always triggered these events.
97+
====
98+
99+
100+
[[child-session-no-interceptor]]
101+
=== Child Session No-Interceptor Behavior
102+
103+
The behavior of `noInterceptor()` for `SharedSessionBuilder` and (the new) `SharedStatelessSessionBuilder` was aligned with the preexisting semantics of this method on `SessionBuilder` and `StatelessSessionBuilder`.
104+
The previous behavior may be recovered by calling `noSessionInterceptorCreation()`.
61105

62106

63107
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

whats-new.adoc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,25 @@ Describes the new features and capabilities added to Hibernate ORM in {version}.
1111

1212
IMPORTANT: If migrating from earlier versions, be sure to also check out the link:{migrationGuide}[Migration Guide] for discussion of impactful changes.
1313

14+
[[child-stateless-sessions]]
15+
== Child StatelessSession
16+
17+
Creation of child `StatelessSession` is now supported, just as with child `Session`.
18+
This is a `StatelessSession` which shares "transactional context" with a parent `Session` or `StatelessSession`.
19+
Use `Session#statelessWithOptions` or `StatelessSession#statelessWithOptions` instead of `#sessionWithOptions`.
20+
21+
====
22+
[source,java]
23+
----
24+
Session parent = ...;
25+
StatelessSession child = parent
26+
.statelessWithOptions()
27+
.connection()
28+
...
29+
.open();
30+
----
31+
====
32+
1433
[[vector-module-enhancements]]
1534
== Hibernate-Vector module enhancements
1635

0 commit comments

Comments
 (0)