You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@grails.apache.org by bo...@apache.org on 2026/05/02 15:35:42 UTC
(grails-core) 13/14: fix(h7): fix withNewSession to open native Hibernate session before binding
This is an automated email from the ASF dual-hosted git repository.
borinquenkid pushed a commit to branch 8.0.x-hibernate7_gorm_enhance
in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit a4b6a26c05ec2d80adf0e2a3092be7784e1fd647
Author: Walter Duque de Estrada <wb...@mac.com>
AuthorDate: Sat May 2 06:04:35 2026 -0500
fix(h7): fix withNewSession to open native Hibernate session before binding
The previous implementation called sessionFactory.getCurrentSession() inside
a DatastoreUtils.executeWithNewSession callback to bind the Hibernate session
under the sessionFactory key. This failed with 'No Session found for current
thread' because DatastoreUtils.executeWithNewSession only creates a lazy
HibernateSession wrapper — no real Hibernate session is opened or bound before
the callback fires.
Fix: open a native Hibernate session via openSession(), bind it to
TransactionSynchronizationManager under the sessionFactory key, then wrap it
in a HibernateSession facade for the caller's closure. This matches the same
contract that HibernateGormStaticApi.withNewSession expects (a HibernateSession
so it can call getNativeSession()) and that GrailsSessionContext.currentSession()
requires (a session bound under sessionFactory key).
Fixes: MultiTenancyUnidirectionalOneToManySpec
Co-authored-by: Copilot <22...@users.noreply.github.com>
---
.../grails/orm/hibernate/HibernateDatastore.java | 32 +++++++++++++++-------
1 file changed, 22 insertions(+), 10 deletions(-)
diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateDatastore.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateDatastore.java
index 9eaeb33d0c..eb1ffde018 100644
--- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateDatastore.java
+++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateDatastore.java
@@ -996,20 +996,32 @@ public class HibernateDatastore extends AbstractDatastore
}
public <T> T withNewSession(final Closure<T> callable) {
- return DatastoreUtils.executeWithNewSession(this, (SessionCallback<T>) session -> {
- boolean bindHibernate = TransactionSynchronizationManager.getResource(sessionFactory) == null;
+ // Open a fresh native Hibernate session, bind it under the sessionFactory key so
+ // that GrailsSessionContext.currentSession() can find it, then wrap it in the GORM
+ // HibernateSession facade before handing off to the caller's closure.
+ // We cannot use sessionFactory.getCurrentSession() here because no session is bound yet;
+ // and we cannot use DatastoreUtils.executeWithNewSession because it creates only a lazy
+ // HibernateSession wrapper without ever binding a real Hibernate session first.
+ org.hibernate.Session hibSession = openSession();
+ boolean bindHibernate = TransactionSynchronizationManager.getResource(sessionFactory) == null;
+ if (bindHibernate) {
+ TransactionSynchronizationManager.bindResource(sessionFactory,
+ new org.grails.orm.hibernate.support.hibernate7.SessionHolder(hibSession));
+ }
+ try {
+ HibernateSession gormSession = new HibernateSession(this, sessionFactory);
+ Closure<T> multiTenantCallable = prepareMultiTenantClosure(callable);
+ return multiTenantCallable.call(gormSession);
+ } finally {
if (bindHibernate) {
- TransactionSynchronizationManager.bindResource(sessionFactory, new org.grails.orm.hibernate.support.hibernate7.SessionHolder(sessionFactory.getCurrentSession()));
+ TransactionSynchronizationManager.unbindResource(sessionFactory);
}
try {
- Closure<T> multiTenantCallable = prepareMultiTenantClosure(callable);
- return multiTenantCallable.call(session);
- } finally {
- if (bindHibernate) {
- TransactionSynchronizationManager.unbindResource(sessionFactory);
- }
+ hibSession.close();
+ } catch (Exception ignored) {
+ // best-effort close
}
- });
+ }
}
@Override