Skip to content

Commit

Permalink
Allow setting a different connection handling mode and auto-close mod…
Browse files Browse the repository at this point in the history
…e for non-injected sessions

With this patch, hopefully people can safely use
EntityManagerFactory.createEntityManager() and opening transactions
manually?

Signed-off-by: Yoann Rodière <yoann@hibernate.org>
  • Loading branch information
yrodiere committed Feb 23, 2021
1 parent 3756ff8 commit d9ed7bc
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -255,9 +255,6 @@ private MergedSettings mergeSettings(PersistenceUnitDescriptor persistenceUnit)
cfg.putIfAbsent(AvailableSettings.CONNECTION_HANDLING,
PhysicalConnectionHandlingMode.DELAYED_ACQUISITION_AND_RELEASE_BEFORE_TRANSACTION_COMPLETION);

// Auto-close sessions before transaction completion, as they should be when using JTA.
cfg.putIfAbsent(AvailableSettings.AUTO_CLOSE_SESSION, "true");

if (readBooleanConfigurationValue(cfg, WRAP_RESULT_SETS)) {
LOG.warn("Wrapping result sets is not supported. Setting " + WRAP_RESULT_SETS + " to false.");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package io.quarkus.hibernate.orm.runtime.session;

import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.SessionBuilder;
import org.hibernate.SessionFactory;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;

/**
* A delegate for opening a JTA-enabled Hibernate ORM session.
* <p>
* The main purpose of this class is to cache session options when possible;
* if we didn't care about caching, we could just replace any call to
*/
public class JTASessionOpener {
public static JTASessionOpener create(SessionFactory sessionFactory) {
final CurrentTenantIdentifierResolver currentTenantIdentifierResolver = sessionFactory
.unwrap(SessionFactoryImplementor.class).getCurrentTenantIdentifierResolver();
if (currentTenantIdentifierResolver == null) {
// No tenant ID resolver: we can cache the options.
return new JTASessionOpener(sessionFactory, createOptions(sessionFactory));
} else {
// There is a tenant ID resolver: we cannot cache the options.
return new JTASessionOpener(sessionFactory, null);
}
}

private static SessionBuilder<?> createOptions(SessionFactory sessionFactory) {
return sessionFactory.withOptions()
.autoClose(true) // .owner() is deprecated as well, so it looks like we need to rely on deprecated code...
.connectionHandlingMode(
PhysicalConnectionHandlingMode.DELAYED_ACQUISITION_AND_RELEASE_BEFORE_TRANSACTION_COMPLETION)
.flushMode(FlushMode.ALWAYS);
}

private final SessionFactory sessionFactory;
private final SessionBuilder<?> cachedOptions;

public JTASessionOpener(SessionFactory sessionFactory, SessionBuilder<?> cachedOptions) {
this.sessionFactory = sessionFactory;
this.cachedOptions = cachedOptions;
}

public Session openSession() {
SessionBuilder<?> options = cachedOptions != null ? cachedOptions : createOptions(sessionFactory);
return options.openSession();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public class TransactionScopedSession implements Session {
private final TransactionManager transactionManager;
private final TransactionSynchronizationRegistry transactionSynchronizationRegistry;
private final SessionFactory sessionFactory;
private final JTASessionOpener jtaSessionOpener;
private final String unitName;
private final String sessionKey;
private final Instance<RequestScopedSessionHolder> requestScopedSessions;
Expand All @@ -71,6 +72,7 @@ public TransactionScopedSession(TransactionManager transactionManager,
this.transactionManager = transactionManager;
this.transactionSynchronizationRegistry = transactionSynchronizationRegistry;
this.sessionFactory = sessionFactory;
this.jtaSessionOpener = JTASessionOpener.create(sessionFactory);
this.unitName = unitName;
this.sessionKey = this.getClass().getSimpleName() + "-" + unitName;
this.requestScopedSessions = requestScopedSessions;
Expand All @@ -82,7 +84,7 @@ SessionResult acquireSession() {
if (session != null) {
return new SessionResult(session, false, true);
}
Session newSession = sessionFactory.openSession();
Session newSession = jtaSessionOpener.openSession();
// The session has automatically joined the JTA transaction when it was constructed.
transactionSynchronizationRegistry.putResource(sessionKey, newSession);
// No need to flush or close the session upon transaction completion:
Expand Down

0 comments on commit d9ed7bc

Please sign in to comment.