diff --git a/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc b/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc index 01a48e490c..c5284ebf53 100644 --- a/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc +++ b/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc @@ -730,5 +730,15 @@ skipUnsupported:: Do the population, but ignore any non-JPA features that would |`hibernate.delay_cdi_access`| `true` or `false` (default value) | Defines delayed access to CDI `BeanManager`. Starting in 5.1 the preferred means for CDI bootstrapping is through `org.hibernate.jpa.event.spi.jpa.ExtendedBeanManager`. + +|`hibernate.allow_update_outside_transaction` | `true` or `false` (default value) a| + +Setting that allows to perform update operations outside of a transaction boundary. + +Accepts two values: + +true:: allows to flush an update out of a transaction +false:: does not allow + |===================================================================================================================================================================================================================================================== 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 1190b0837e..048b83cdbb 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/SessionFactoryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/SessionFactoryBuilder.java @@ -687,6 +687,8 @@ public interface SessionFactoryBuilder { */ SessionFactoryBuilder applySqlFunction(String registrationName, SQLFunction sqlFunction); + SessionFactoryBuilder allowOutOfTransactionUpdateOperations(boolean allow); + /** * 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 fa11eb6329..f6b3307df0 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 @@ -106,6 +106,7 @@ import static org.hibernate.cfg.AvailableSettings.USE_SECOND_LEVEL_CACHE; import static org.hibernate.cfg.AvailableSettings.USE_SQL_COMMENTS; 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; /** @@ -464,6 +465,12 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement return this; } + @Override + public SessionFactoryBuilder allowOutOfTransactionUpdateOperations(boolean allow) { + this.options.allowOutOfTransactionUpdateOperations = allow; + return this; + } + @Override @SuppressWarnings("unchecked") public T unwrap(Class type) { @@ -511,6 +518,7 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement private boolean flushBeforeCompletionEnabled; private boolean autoCloseSessionEnabled; private boolean jtaTransactionAccessEnabled; + private boolean allowOutOfTransactionUpdateOperations; // (JTA) transaction handling private boolean jtaTrackByThread; @@ -542,6 +550,7 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement private boolean orderUpdatesEnabled; private boolean orderInsertsEnabled; + // multi-tenancy private MultiTenancyStrategy multiTenancyStrategy; private CurrentTenantIdentifierResolver currentTenantIdentifierResolver; @@ -738,6 +747,11 @@ 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 + ); } private static Interceptor determineInterceptor(Map configurationSettings, StrategySelector strategySelector) { @@ -868,6 +882,10 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement return jtaTransactionAccessEnabled; } + public boolean isAllowOutOfTransactionUpdateOperations() { + return allowOutOfTransactionUpdateOperations; + } + @Override public Object getBeanManagerReference() { return beanManagerReference; @@ -1159,6 +1177,10 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement return options.isJtaTransactionAccessEnabled(); } + public boolean isAllowOutOfTransactionUpdateOperations() { + return options.isAllowOutOfTransactionUpdateOperations(); + } + @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 a728c28beb..c081bd7a9d 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 @@ -53,6 +53,8 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions { private final boolean autoCloseSessionEnabled; private boolean jtaTransactionAccessEnabled; + private boolean allowOutOfTransactionUpdateOperations; + // transaction handling private final boolean jtaTrackByThread; private final boolean preferUserTransaction; @@ -126,6 +128,7 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions { this.jpaBootstrap = state.isJpaBootstrap(); this.jtaTransactionAccessEnabled = state.isJtaTransactionAccessEnabled(); + this.allowOutOfTransactionUpdateOperations = state.isAllowOutOfTransactionUpdateOperations(); this.sessionFactoryName = state.getSessionFactoryName(); this.sessionFactoryNameAlsoJndiName = state.isSessionFactoryNameAlsoJndiName(); @@ -363,6 +366,11 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions { return procedureParameterNullPassingEnabled; } + @Override + public boolean isAllowOutOfTransactionUpdateOperations() { + return allowOutOfTransactionUpdateOperations; + } + @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 6369809c20..952fa2f3ff 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 @@ -48,6 +48,8 @@ public interface SessionFactoryOptionsState { boolean isJtaTransactionAccessEnabled(); + boolean isAllowOutOfTransactionUpdateOperations(); + 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 ea1d2d5775..594f8e0a07 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 @@ -362,6 +362,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 67cca07360..8643d03914 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 @@ -213,6 +213,11 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp return delegate.isProcedureParameterNullPassingEnabled(); } + @Override + public boolean isAllowOutOfTransactionUpdateOperations() { + return delegate.isAllowOutOfTransactionUpdateOperations(); + } + @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 f3e1cd44e1..11e71dc2b0 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 @@ -201,4 +201,6 @@ public interface SessionFactoryOptions { boolean isPreferUserTransaction(); boolean isProcedureParameterNullPassingEnabled(); + + boolean isAllowOutOfTransactionUpdateOperations(); } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index b34e16b61a..189f8cdd97 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -1511,4 +1511,17 @@ public interface AvailableSettings { */ String ALLOW_JTA_TRANSACTION_ACCESS = "hibernate.jta.allowTransactionAccess"; + /** + * Setting that allows to perform update operations outside of a transaction boundary. + * + * Since version 5.2 Hibernate conforms with the JPA specification and does not allow anymore + * to flush any update out of a transaction boundary. + *

+ * Values are: {@code true} to allow flush operations out of a transaction, {@code false} to disallow. + *

+ * The default behavior is {@code false} + * + * @since 5.2 + */ + String ALLOW_UPDATE_OUTSIDE_TRANSACTION = "hibernate.allow_update_outside_transaction"; } 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 0a1b3f3582..47451246fe 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -63,7 +63,6 @@ import org.hibernate.ObjectNotFoundException; import org.hibernate.QueryException; import org.hibernate.ReplicationMode; import org.hibernate.ScrollMode; -import org.hibernate.ScrollableResults; import org.hibernate.Session; import org.hibernate.SessionEventListener; import org.hibernate.SessionException; @@ -235,6 +234,7 @@ public final class SessionImpl private transient boolean autoClose; private transient int dontFlushFromFind; + private transient boolean disallowOutOfTransactionUpdateOperations; private transient ExceptionMapper exceptionMapper; private transient ManagedFlushChecker managedFlushChecker; @@ -253,6 +253,7 @@ public final class SessionImpl this.autoClear = options.shouldAutoClear(); this.autoClose = options.shouldAutoClose(); + this.disallowOutOfTransactionUpdateOperations = !factory.getSessionFactoryOptions().isAllowOutOfTransactionUpdateOperations(); if ( options instanceof SharedSessionCreationOptions && ( (SharedSessionCreationOptions) options ).isTransactionCoordinatorShared() ) { final SharedSessionCreationOptions sharedOptions = (SharedSessionCreationOptions) options; @@ -3388,7 +3389,7 @@ public final class SessionImpl } private void checkTransactionNeeded() { - if ( !isTransactionInProgress() ) { + if ( disallowOutOfTransactionUpdateOperations && !isTransactionInProgress() ) { throw new TransactionRequiredException( "no transaction is in progress" ); } }