diff --git a/hibernate-core/src/main/java/org/hibernate/boot/SessionFactoryBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/SessionFactoryBuilder.java index 048b83cdbb..4a112466f9 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/SessionFactoryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/SessionFactoryBuilder.java @@ -689,6 +689,14 @@ public interface SessionFactoryBuilder { SessionFactoryBuilder allowOutOfTransactionUpdateOperations(boolean allow); + /** + * Should resources held by {@link javax.persistence.EntityManager} instance be released immediately on close? + *

+ * The other option is to release them as part of an afterQuery-transaction callback. + * + */ + SessionFactoryBuilder enableReleaseResourcesOnCloseEnabled(boolean enable); + /** * Allows unwrapping this builder as another, more specific type. * diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryBuilderImpl.java index f6b3307df0..a5e56f1fd5 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryBuilderImpl.java @@ -108,6 +108,7 @@ import static org.hibernate.cfg.AvailableSettings.USE_STRUCTURED_CACHE; import static org.hibernate.cfg.AvailableSettings.WRAP_RESULT_SETS; import static org.hibernate.cfg.AvailableSettings.ALLOW_UPDATE_OUTSIDE_TRANSACTION; import static org.hibernate.engine.config.spi.StandardConverters.BOOLEAN; +import static org.hibernate.jpa.AvailableSettings.DISCARD_PC_ON_CLOSE; /** * @author Gail Badner @@ -471,6 +472,12 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement return this; } + @Override + public SessionFactoryBuilder enableReleaseResourcesOnCloseEnabled(boolean enable) { + this.options.releaseResourcesOnCloseEnabled = enable; + return this; + } + @Override @SuppressWarnings("unchecked") public T unwrap(Class type) { @@ -519,6 +526,7 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement private boolean autoCloseSessionEnabled; private boolean jtaTransactionAccessEnabled; private boolean allowOutOfTransactionUpdateOperations; + private boolean releaseResourcesOnCloseEnabled; // (JTA) transaction handling private boolean jtaTrackByThread; @@ -747,11 +755,18 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement this.commentsEnabled = ConfigurationHelper.getBoolean( USE_SQL_COMMENTS, configurationSettings ); this.preferUserTransaction = ConfigurationHelper.getBoolean( PREFER_USER_TRANSACTION, configurationSettings, false ); + this.allowOutOfTransactionUpdateOperations = ConfigurationHelper.getBoolean( ALLOW_UPDATE_OUTSIDE_TRANSACTION, configurationSettings, false ); + + this.releaseResourcesOnCloseEnabled = ConfigurationHelper.getBoolean( + DISCARD_PC_ON_CLOSE, + configurationSettings, + false + ); } private static Interceptor determineInterceptor(Map configurationSettings, StrategySelector strategySelector) { @@ -886,6 +901,11 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement return allowOutOfTransactionUpdateOperations; } + @Override + public boolean isReleaseResourcesOnCloseEnabled() { + return releaseResourcesOnCloseEnabled; + } + @Override public Object getBeanManagerReference() { return beanManagerReference; @@ -1181,6 +1201,11 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement return options.isAllowOutOfTransactionUpdateOperations(); } + @Override + public boolean isReleaseResourcesOnCloseEnabled(){ + return options.releaseResourcesOnCloseEnabled; + } + @Override public Object getBeanManagerReference() { return options.getBeanManagerReference(); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsImpl.java index c081bd7a9d..2ca895a6b3 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsImpl.java @@ -54,6 +54,7 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions { private boolean jtaTransactionAccessEnabled; private boolean allowOutOfTransactionUpdateOperations; + private boolean releaseResourcesOnCloseEnabled; // transaction handling private final boolean jtaTrackByThread; @@ -371,6 +372,11 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions { return allowOutOfTransactionUpdateOperations; } + @Override + public boolean isReleaseResourcesOnCloseEnabled() { + return releaseResourcesOnCloseEnabled; + } + @Override public boolean isSecondLevelCacheEnabled() { return secondLevelCacheEnabled; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsState.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsState.java index 952fa2f3ff..876eb363a2 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsState.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsState.java @@ -50,6 +50,8 @@ public interface SessionFactoryOptionsState { boolean isAllowOutOfTransactionUpdateOperations(); + boolean isReleaseResourcesOnCloseEnabled(); + Object getBeanManagerReference(); Object getValidatorFactoryReference(); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryBuilder.java index 594f8e0a07..fa125f9f52 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryBuilder.java @@ -368,6 +368,12 @@ public abstract class AbstractDelegatingSessionFactoryBuilder S unwrap(Class type) { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java index 8643d03914..2b327b9d20 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java @@ -218,6 +218,11 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp return delegate.isAllowOutOfTransactionUpdateOperations(); } + @Override + public boolean isReleaseResourcesOnCloseEnabled() { + return delegate.isReleaseResourcesOnCloseEnabled(); + } + @Override public boolean isSecondLevelCacheEnabled() { return delegate.isSecondLevelCacheEnabled(); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java index 11e71dc2b0..129121e4e8 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java @@ -203,4 +203,6 @@ public interface SessionFactoryOptions { boolean isProcedureParameterNullPassingEnabled(); boolean isAllowOutOfTransactionUpdateOperations(); + + boolean isReleaseResourcesOnCloseEnabled(); } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java index 793b0a922e..1a990f5664 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java @@ -114,7 +114,8 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont private CacheMode cacheMode; - private boolean closed; + protected boolean closed; + protected boolean waitingForAutoClose; // transient & non-final for Serialization purposes - ugh private transient SessionEventListenerManagerImpl sessionEventsManager = new SessionEventListenerManagerImpl(); @@ -306,6 +307,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont protected void setClosed() { closed = true; + waitingForAutoClose = false; cleanupOnClose(); } @@ -342,6 +344,9 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont @Override public boolean isTransactionInProgress() { + if ( waitingForAutoClose ) { + return transactionCoordinator.isTransactionActive(); + } return !isClosed() && transactionCoordinator.isTransactionActive(); } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index 0991b6c641..1651292d6c 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -242,6 +242,8 @@ public final class SessionImpl private transient LoadEvent loadEvent; //cached LoadEvent instance + private transient boolean discardOnClose; + public SessionImpl(SessionFactoryImpl factory, SessionCreationOptions options) { super( factory, options ); @@ -254,6 +256,7 @@ public final class SessionImpl this.autoClear = options.shouldAutoClear(); this.autoClose = options.shouldAutoClose(); this.disallowOutOfTransactionUpdateOperations = !factory.getSessionFactoryOptions().isAllowOutOfTransactionUpdateOperations(); + this.discardOnClose = getFactory().getSessionFactoryOptions().isReleaseResourcesOnCloseEnabled(); if ( options instanceof SharedSessionCreationOptions && ( (SharedSessionCreationOptions) options ).isTransactionCoordinatorShared() ) { final SharedSessionCreationOptions sharedOptions = (SharedSessionCreationOptions) options; @@ -302,6 +305,7 @@ public final class SessionImpl private void applyEntityManagerSpecificProperties() { for ( String key : ENTITY_MANAGER_SPECIFIC_PROPERTIES ) { + final Map properties = getFactory().getProperties(); if ( getFactory().getProperties().containsKey( key ) ) { this.properties.put( key, getFactory().getProperties().get( key ) ); } @@ -398,28 +402,26 @@ public final class SessionImpl // todo : we want this check if usage is JPA, but not native Hibernate usage if ( getSessionFactory().getSessionFactoryOptions().isJpaBootstrap() ) { + // Original hibernate-entitymanager EM#close behavior + checkSessionFactoryOpen(); checkOpen(); + if ( discardOnClose || !isTransactionInProgress() ) { + super.close(); + } + else { + //Otherwise, session auto-close will be enabled by shouldAutoCloseSession(). + waitingForAutoClose = true; + closed = true; + } } + else { - super.close(); + super.close(); - if ( getFactory().getStatistics().isStatisticsEnabled() ) { - getFactory().getStatistics().closeSession(); + if ( getFactory().getStatistics().isStatisticsEnabled() ) { + getFactory().getStatistics().closeSession(); + } } - -// Original hibernate-entitymanager EM#close behavior -// does any of this need to be integrated? -// checkSessionFactoryOpen(); -// checkOpen(); -// -// if ( discardOnClose || !isTransactionInProgress() ) { -// //close right now -// if ( session != null ) { -// session.close(); -// } -// } -// // Otherwise, session auto-close will be enabled by shouldAutoCloseSession(). -// open = false; } @Override @@ -446,7 +448,7 @@ public final class SessionImpl checkSessionFactoryOpen(); checkTransactionSynchStatus(); try { - return !isClosed(); + return !isClosed() && !waitingForAutoClose ; } catch (HibernateException he) { throw exceptionConverter.convert( he ); @@ -465,17 +467,20 @@ public final class SessionImpl } private void managedFlush() { - if ( isClosed() ) { + if ( isClosed() && !waitingForAutoClose ) { log.trace( "Skipping auto-flush due to session closed" ); return; } log.trace( "Automatically flushing session" ); - flush(); + doFlush(); } @Override public boolean shouldAutoClose() { - if ( isClosed() ) { + if ( waitingForAutoClose ) { + return true; + } + else if ( isClosed() ) { return false; } else if ( sessionOwner != null ) { @@ -1383,10 +1388,13 @@ public final class SessionImpl @Override public void flush() throws HibernateException { checkOpen(); + doFlush(); + } + + private void doFlush() { checkTransactionNeeded(); checkTransactionSynchStatus(); - try { if ( persistenceContext.getCascadeLevel() > 0 ) { throw new HibernateException( "Flush during cascade is dangerous" ); @@ -2224,14 +2232,18 @@ public final class SessionImpl @Override public ActionQueue getActionQueue() { - checkOpen(); + if ( !waitingForAutoClose ) { + checkOpen(); + } // checkTransactionSynchStatus(); return actionQueue; } @Override public PersistenceContext getPersistenceContext() { - checkOpen(); + if ( !waitingForAutoClose ) { + checkOpen(); + } // checkTransactionSynchStatus(); return persistenceContext; } @@ -3148,8 +3160,7 @@ public final class SessionImpl @Override public void flushBeforeTransactionCompletion() { - final boolean doFlush = ! isClosed() - && isTransactionFlushable() + final boolean doFlush = isTransactionFlushable() && getHibernateFlushMode() != FlushMode.MANUAL; try { diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java index ac7faff3ab..32a3aef5d0 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java @@ -145,7 +145,6 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil private final StandardServiceRegistry standardServiceRegistry; private final ManagedResources managedResources; private final MetadataBuilderImplementor metamodelBuilder; - private final SettingsImpl settings; private static class JpaEntityNotFoundDelegate implements EntityNotFoundDelegate, Serializable { /** @@ -200,7 +199,7 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil // Build the "standard" service registry ssrBuilder.applySettings( configurationValues ); - this.settings = configure( ssrBuilder ); + configure( ssrBuilder ); this.standardServiceRegistry = ssrBuilder.build(); configure( standardServiceRegistry, mergedSettings ); @@ -580,11 +579,10 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil return new CacheRegionDefinition( cacheType, role, usage, region, lazyProperty ); } - private SettingsImpl configure(StandardServiceRegistryBuilder ssrBuilder) { - final SettingsImpl settings = new SettingsImpl(); + private void configure(StandardServiceRegistryBuilder ssrBuilder) { applyJdbcConnectionProperties( ssrBuilder ); - applyTransactionProperties( ssrBuilder, settings ); + applyTransactionProperties( ssrBuilder ); // flush beforeQuery completion validation if ( "true".equals( configurationValues.get( Environment.FLUSH_BEFORE_COMPLETION ) ) ) { @@ -592,11 +590,6 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil LOG.definingFlushBeforeCompletionIgnoredInHem( Environment.FLUSH_BEFORE_COMPLETION ); } - final Object value = configurationValues.get( DISCARD_PC_ON_CLOSE ); - if ( value != null ) { - settings.setReleaseResourcesOnCloseEnabled( "true".equals( value ) ); - } - // final StrategySelector strategySelector = ssrBuilder.getBootstrapServiceRegistry().getService( StrategySelector.class ); // final Object interceptorSetting = configurationValues.remove( AvailableSettings.SESSION_INTERCEPTOR ); // if ( interceptorSetting != null ) { @@ -604,8 +597,6 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil // loadSessionInterceptorClass( interceptorSetting, strategySelector ) // ); // } - - return settings; } private void applyJdbcConnectionProperties(StandardServiceRegistryBuilder ssrBuilder) { @@ -646,7 +637,7 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil } } - private void applyTransactionProperties(StandardServiceRegistryBuilder ssrBuilder, SettingsImpl settings) { + private void applyTransactionProperties(StandardServiceRegistryBuilder ssrBuilder) { PersistenceUnitTransactionType txnType = PersistenceUnitTransactionTypeHelper.interpretTransactionType( configurationValues.get( JPA_TRANSACTION_TYPE ) ); @@ -657,7 +648,6 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil // is it more appropriate to have this be based on bootstrap entry point (EE vs SE)? txnType = PersistenceUnitTransactionType.RESOURCE_LOCAL; } - settings.setTransactionType( txnType ); boolean hasTxStrategy = configurationValues.containsKey( TRANSACTION_COORDINATOR_STRATEGY ); if ( hasTxStrategy ) { LOG.overridingTransactionStrategyDangerous( TRANSACTION_COORDINATOR_STRATEGY ); diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/SettingsImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/SettingsImpl.java deleted file mode 100644 index 797ae1e17c..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/SettingsImpl.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.jpa.boot.internal; - -import javax.persistence.spi.PersistenceUnitTransactionType; - -import org.hibernate.Interceptor; -import org.hibernate.jpa.boot.spi.Settings; - -/** - * @author Steve Ebersole - */ -public class SettingsImpl implements Settings { - private PersistenceUnitTransactionType transactionType; - private boolean releaseResourcesOnCloseEnabled; - private Class sessionInterceptorClass; - - @Override - public PersistenceUnitTransactionType getTransactionType() { - return transactionType; - } - - public SettingsImpl setTransactionType(PersistenceUnitTransactionType transactionType) { - this.transactionType = transactionType; - return this; - } - - @Override - public boolean isReleaseResourcesOnCloseEnabled() { - return releaseResourcesOnCloseEnabled; - } - - public SettingsImpl setReleaseResourcesOnCloseEnabled(boolean releaseResourcesOnCloseEnabled) { - this.releaseResourcesOnCloseEnabled = releaseResourcesOnCloseEnabled; - return this; - } - - @Override - public Class getSessionInterceptorClass() { - return sessionInterceptorClass; - } - - public SettingsImpl setSessionInterceptorClass(Class sessionInterceptorClass) { - this.sessionInterceptorClass = sessionInterceptorClass; - return this; - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/Settings.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/Settings.java deleted file mode 100644 index b775b32e89..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/Settings.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.jpa.boot.spi; - -import javax.persistence.spi.PersistenceUnitTransactionType; - -import org.hibernate.Interceptor; - -/** - * @author Steve Ebersole - */ -public interface Settings { - public PersistenceUnitTransactionType getTransactionType(); - - /** - * Should resources held by {@link javax.persistence.EntityManager} instance be released immediately on close? - *

- * The other option is to release them as part of an afterQuery-transaction callback. - * - * @return {@code true}/{@code false} - */ - public boolean isReleaseResourcesOnCloseEnabled(); - - public Class getSessionInterceptorClass(); - -}