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 Gail Badner
parent fd93c89d95
commit 9d04140fc6
6 changed files with 41 additions and 22 deletions

View File

@ -156,6 +156,11 @@ public boolean isTransactionInProgress() {
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.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 @@ default long getTimestamp() {
*/
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.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 boolean isTransactionInProgress() {
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 @@ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFound
entityNameResolver = new CoordinatingEntityNameResolver( factory, interceptor );
exceptionConverter = new ExceptionConverterImpl( this );
this.disallowOutOfTransactionUpdateOperations = !getFactory().getSessionFactoryOptions().isAllowOutOfTransactionUpdateOperations();
}
}

View File

@ -238,7 +238,6 @@ public final class SessionImpl
private transient int dontFlushFromFind;
private transient boolean disallowOutOfTransactionUpdateOperations;
private transient ExceptionMapper exceptionMapper;
private transient ManagedFlushChecker managedFlushChecker;
@ -262,7 +261,7 @@ public SessionImpl(SessionFactoryImpl factory, SessionCreationOptions options) {
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() ) {
@ -1441,7 +1440,7 @@ public void flush() throws HibernateException {
}
private void doFlush() {
checkTransactionNeeded();
checkTransactionNeededForUpdateOperation();
checkTransactionSynchStatus();
try {
@ -3474,7 +3473,7 @@ public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode
if ( lockModeType != null ) {
if ( !LockModeType.NONE.equals( lockModeType) ) {
checkTransactionNeeded();
checkTransactionNeededForUpdateOperation();
}
lockOptions = buildLockOptions( lockModeType, properties );
loadAccess.with( lockOptions );
@ -3547,10 +3546,8 @@ private CacheStoreMode determineCacheStoreMode(Map<String, Object> settings) {
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
@ -3576,7 +3573,7 @@ public void lock(Object entity, LockModeType lockModeType) {
@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" );
@ -3618,7 +3615,7 @@ public void refresh(Object entity, LockModeType lockModeType, Map<String, Object
if ( lockModeType != null ) {
if ( !LockModeType.NONE.equals( lockModeType) ) {
checkTransactionNeeded();
checkTransactionNeededForUpdateOperation();
}
lockOptions = buildLockOptions( lockModeType, properties );
@ -3996,7 +3993,6 @@ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFound
initializeFromSessionOwner( null );
this.disallowOutOfTransactionUpdateOperations = !getFactory().getSessionFactoryOptions().isAllowOutOfTransactionUpdateOperations();
this.discardOnClose = getFactory().getSessionFactoryOptions().isReleaseResourcesOnCloseEnabled();
}
}

View File

@ -25,7 +25,6 @@
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 @@ protected ProcedureOutputs outputs() {
@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

@ -1582,13 +1582,8 @@ public static <R> R uniqueElement(List<R> list) throws NonUniqueResultException
@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();