HHH-13262 - javax.persistence.TransactionRequiredException: Executing an update/delete query

This commit is contained in:
Andrea Boriero 2019-02-12 11:22:34 +00:00 committed by gbadner
parent 4256f300dd
commit ef3b07bd73
6 changed files with 41 additions and 22 deletions

View File

@ -157,6 +157,11 @@ public class SessionDelegatorBaseImpl implements SessionImplementor {
return delegate.isTransactionInProgress();
}
@Override
public void checkTransactionNeededForUpdateOperation(String exceptionMessage) {
delegate.checkTransactionNeededForUpdateOperation( exceptionMessage );
}
@Override
public LockOptions getLockRequest(LockModeType lockModeType, Map<String, Object> properties) {
return delegate.getLockRequest( lockModeType, properties );

View File

@ -12,6 +12,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import javax.persistence.FlushModeType;
import javax.persistence.TransactionRequiredException;
import org.hibernate.CacheMode;
import org.hibernate.Criteria;
@ -180,6 +181,18 @@ public interface SharedSessionContractImplementor
*/
boolean isTransactionInProgress();
/**
* Check if an active Transaction is necessary for the update operation to be executed.
* If an active Transaction is necessary but it is not then a TransactionRequiredException is raised.
*
* @param exceptionMessage, the message to use for the TransactionRequiredException
*/
default void checkTransactionNeededForUpdateOperation(String exceptionMessage) {
if ( !isTransactionInProgress() ) {
throw getExceptionConverter().convert( new TransactionRequiredException( exceptionMessage ) );
}
}
/**
* Provides access to the underlying transaction or creates a new transaction if
* one does not already exist or is active. This is primarily for internal or

View File

@ -15,6 +15,7 @@ import java.util.List;
import java.util.TimeZone;
import java.util.UUID;
import javax.persistence.FlushModeType;
import javax.persistence.TransactionRequiredException;
import javax.persistence.Tuple;
import org.hibernate.AssertionFailure;
@ -128,6 +129,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
protected boolean closed;
protected boolean waitingForAutoClose;
private transient boolean disallowOutOfTransactionUpdateOperations;
// transient & non-final for Serialization purposes - ugh
private transient SessionEventListenerManagerImpl sessionEventsManager = new SessionEventListenerManagerImpl();
@ -141,6 +143,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
public AbstractSharedSessionContract(SessionFactoryImpl factory, SessionCreationOptions options) {
this.factory = factory;
this.cacheTransactionSync = factory.getCache().getRegionFactory().createTransactionContext( this );
this.disallowOutOfTransactionUpdateOperations = !factory.getSessionFactoryOptions().isAllowOutOfTransactionUpdateOperations();
this.flushMode = options.getInitialSessionFlushMode();
@ -389,6 +392,13 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
return !isClosed() && transactionCoordinator.isTransactionActive();
}
@Override
public void checkTransactionNeededForUpdateOperation(String exceptionMessage) {
if ( disallowOutOfTransactionUpdateOperations && !isTransactionInProgress() ) {
throw getExceptionConverter().convert( new TransactionRequiredException( exceptionMessage ) );
}
}
@Override
public Transaction getTransaction() throws HibernateException {
if ( getFactory().getSessionFactoryOptions().getJpaCompliance().isJpaTransactionComplianceEnabled() ) {
@ -1133,5 +1143,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
entityNameResolver = new CoordinatingEntityNameResolver( factory, interceptor );
exceptionConverter = new ExceptionConverterImpl( this );
this.disallowOutOfTransactionUpdateOperations = !getFactory().getSessionFactoryOptions().isAllowOutOfTransactionUpdateOperations();
}
}

View File

@ -242,7 +242,6 @@ public final class SessionImpl
private transient int dontFlushFromFind;
private transient boolean disallowOutOfTransactionUpdateOperations;
private transient ExceptionMapper exceptionMapper;
private transient ManagedFlushChecker managedFlushChecker;
@ -266,7 +265,7 @@ public final class SessionImpl
this.autoClear = options.shouldAutoClear();
this.autoClose = options.shouldAutoClose();
this.queryParametersValidationEnabled = options.isQueryParametersValidationEnabled();
this.disallowOutOfTransactionUpdateOperations = !factory.getSessionFactoryOptions().isAllowOutOfTransactionUpdateOperations();
this.discardOnClose = getFactory().getSessionFactoryOptions().isReleaseResourcesOnCloseEnabled();
if ( options instanceof SharedSessionCreationOptions && ( (SharedSessionCreationOptions) options ).isTransactionCoordinatorShared() ) {
@ -1471,7 +1470,7 @@ public final class SessionImpl
}
private void doFlush() {
checkTransactionNeeded();
checkTransactionNeededForUpdateOperation();
checkTransactionSynchStatus();
try {
@ -3536,7 +3535,7 @@ public final class SessionImpl
if ( lockModeType != null ) {
if ( !LockModeType.NONE.equals( lockModeType) ) {
checkTransactionNeeded();
checkTransactionNeededForUpdateOperation();
}
lockOptions = buildLockOptions( lockModeType, properties );
loadAccess.with( lockOptions );
@ -3608,10 +3607,8 @@ public final class SessionImpl
return ( CacheStoreMode ) settings.get( JPA_SHARED_CACHE_STORE_MODE );
}
private void checkTransactionNeeded() {
if ( disallowOutOfTransactionUpdateOperations && !isTransactionInProgress() ) {
throw new TransactionRequiredException( "no transaction is in progress" );
}
private void checkTransactionNeededForUpdateOperation() {
checkTransactionNeededForUpdateOperation( "no transaction is in progress" );
}
@Override
@ -3637,7 +3634,7 @@ public final class SessionImpl
@Override
public void lock(Object entity, LockModeType lockModeType, Map<String, Object> properties) {
checkOpen();
checkTransactionNeeded();
checkTransactionNeededForUpdateOperation();
if ( !contains( entity ) ) {
throw new IllegalArgumentException( "entity not in the persistence context" );
@ -3679,7 +3676,7 @@ public final class SessionImpl
if ( lockModeType != null ) {
if ( !LockModeType.NONE.equals( lockModeType) ) {
checkTransactionNeeded();
checkTransactionNeededForUpdateOperation();
}
lockOptions = buildLockOptions( lockModeType, properties );
@ -4011,7 +4008,6 @@ public final class SessionImpl
initializeFromSessionOwner( null );
this.disallowOutOfTransactionUpdateOperations = !getFactory().getSessionFactoryOptions().isAllowOutOfTransactionUpdateOperations();
this.discardOnClose = getFactory().getSessionFactoryOptions().isReleaseResourcesOnCloseEnabled();
}
}

View File

@ -25,7 +25,6 @@ import javax.persistence.NonUniqueResultException;
import javax.persistence.Parameter;
import javax.persistence.ParameterMode;
import javax.persistence.TemporalType;
import javax.persistence.TransactionRequiredException;
import org.hibernate.HibernateException;
import org.hibernate.engine.ResultSetMappingDefinition;
@ -636,9 +635,8 @@ public class ProcedureCallImpl<R>
@Override
public int executeUpdate() {
if ( ! getProducer().isTransactionInProgress() ) {
throw new TransactionRequiredException( "javax.persistence.Query.executeUpdate requires active transaction" );
}
getProducer().checkTransactionNeededForUpdateOperation(
"javax.persistence.Query.executeUpdate requires active transaction" );
// the expectation is that there is just one Output, of type UpdateCountOutput
try {

View File

@ -1606,13 +1606,8 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
@Override
public int executeUpdate() throws HibernateException {
if ( ! getProducer().isTransactionInProgress() ) {
throw getProducer().getExceptionConverter().convert(
new TransactionRequiredException(
"Executing an update/delete query"
)
);
}
getProducer().checkTransactionNeededForUpdateOperation( "Executing an update/delete query" );
beforeQuery();
try {
return doExecuteUpdate();