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 Jan 21, 2021
1 parent 01f465b commit 9c82b0d
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.hibernate.SessionFactory;
import org.jboss.logging.Logger;

import io.quarkus.hibernate.orm.runtime.session.JTASessionOptions;

@Singleton
public class JPAConfig {

Expand Down Expand Up @@ -114,13 +117,28 @@ EntityManagerFactory get() {
throw new IllegalStateException("Persistence unit is closed");
}
if (value == null) {
value = Persistence.createEntityManagerFactory(name);
value = create();
}
}
}
return value;
}

private EntityManagerFactory create() {
EntityManagerFactory result = Persistence.createEntityManagerFactory(name);
try {
JTASessionOptions.init(result.unwrap(SessionFactory.class));
} catch (RuntimeException e) {
try {
result.close();
} catch (RuntimeException e2) {
e.addSuppressed(e2);
throw e;
}
}
return result;
}

public synchronized void close() {
closed = true;
EntityManagerFactory emf = this.value;
Expand Down
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,23 @@
package io.quarkus.hibernate.orm.runtime.session;

import org.hibernate.FlushMode;
import org.hibernate.SessionBuilder;
import org.hibernate.SessionFactory;
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;

public class JTASessionOptions {
private static final String KEY = JTASessionOptions.class.getName();

public static void init(SessionFactory sessionFactory) {
SessionBuilder<?> options = 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);
sessionFactory.getProperties().put(KEY, options);
}

public static SessionBuilder<?> get(SessionFactory sessionFactory) {
return (SessionBuilder<?>) sessionFactory.getProperties().get(KEY);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.hibernate.NaturalIdLoadAccess;
import org.hibernate.ReplicationMode;
import org.hibernate.Session;
import org.hibernate.SessionBuilder;
import org.hibernate.SessionEventListener;
import org.hibernate.SessionFactory;
import org.hibernate.SharedSessionBuilder;
Expand All @@ -59,6 +60,7 @@ public class TransactionScopedSession implements Session {
private final TransactionManager transactionManager;
private final TransactionSynchronizationRegistry transactionSynchronizationRegistry;
private final SessionFactory sessionFactory;
private final SessionBuilder<?> jtaSessionOptions;
private final String unitName;
private final String sessionKey;
private final Instance<RequestScopedSessionHolder> requestScopedSessions;
Expand All @@ -71,6 +73,7 @@ public TransactionScopedSession(TransactionManager transactionManager,
this.transactionManager = transactionManager;
this.transactionSynchronizationRegistry = transactionSynchronizationRegistry;
this.sessionFactory = sessionFactory;
this.jtaSessionOptions = JTASessionOptions.get(sessionFactory);
this.unitName = unitName;
this.sessionKey = this.getClass().getSimpleName() + "-" + unitName;
this.requestScopedSessions = requestScopedSessions;
Expand All @@ -82,7 +85,7 @@ SessionResult acquireSession() {
if (session != null) {
return new SessionResult(session, false, true);
}
Session newSession = sessionFactory.openSession();
Session newSession = jtaSessionOptions.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 9c82b0d

Please sign in to comment.