HHH-12487 - Calling getTransaction() on a closed EntityManager

This commit is contained in:
Andrea Boriero 2018-04-15 18:57:57 +01:00
parent 19f78bbd3d
commit 291d4a3eea
2 changed files with 52 additions and 26 deletions

View File

@ -12,6 +12,7 @@ import org.hibernate.HibernateException;
import org.hibernate.TransactionException; import org.hibernate.TransactionException;
import org.hibernate.engine.spi.ExceptionConverter; import org.hibernate.engine.spi.ExceptionConverter;
import org.hibernate.engine.transaction.spi.TransactionImplementor; import org.hibernate.engine.transaction.spi.TransactionImplementor;
import org.hibernate.internal.AbstractSharedSessionContract;
import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreLogging;
import org.hibernate.jpa.spi.JpaCompliance; import org.hibernate.jpa.spi.JpaCompliance;
import org.hibernate.resource.transaction.spi.TransactionCoordinator; import org.hibernate.resource.transaction.spi.TransactionCoordinator;
@ -31,29 +32,38 @@ public class TransactionImpl implements TransactionImplementor {
private final TransactionCoordinator transactionCoordinator; private final TransactionCoordinator transactionCoordinator;
private final ExceptionConverter exceptionConverter; private final ExceptionConverter exceptionConverter;
private final JpaCompliance jpaCompliance; private final JpaCompliance jpaCompliance;
private final AbstractSharedSessionContract session;
private TransactionDriver transactionDriverControl; private TransactionDriver transactionDriverControl;
public TransactionImpl( public TransactionImpl(
TransactionCoordinator transactionCoordinator, TransactionCoordinator transactionCoordinator,
ExceptionConverter exceptionConverter, ExceptionConverter exceptionConverter,
JpaCompliance jpaCompliance) { AbstractSharedSessionContract session) {
this.transactionCoordinator = transactionCoordinator; this.transactionCoordinator = transactionCoordinator;
this.exceptionConverter = exceptionConverter; this.exceptionConverter = exceptionConverter;
this.jpaCompliance = jpaCompliance; this.jpaCompliance = session.getFactory().getSessionFactoryOptions().getJpaCompliance();
this.session = session;
this.transactionDriverControl = transactionCoordinator.getTransactionDriverControl(); if ( session.isOpen() && transactionCoordinator.isActive() ) {
this.transactionDriverControl = transactionCoordinator.getTransactionDriverControl();
}
else {
LOG.debug( "TransactionImpl created on closed Session/EntityManager" );
}
LOG.debugf( if ( LOG.isDebugEnabled() ) {
"On TransactionImpl creation, JpaCompliance#isJpaTransactionComplianceEnabled == %s", LOG.debugf(
jpaCompliance.isJpaTransactionComplianceEnabled() "On TransactionImpl creation, JpaCompliance#isJpaTransactionComplianceEnabled == %s",
); jpaCompliance.isJpaTransactionComplianceEnabled()
);
}
} }
@Override @Override
public void begin() { public void begin() {
if ( !transactionCoordinator.isActive() ) { if ( !session.isOpen() ) {
throw new TransactionException( "Cannot begin Transaction on closed Session/EntityManager" ); throw new IllegalStateException( "Cannot begin Transaction on closed Session/EntityManager" );
} }
if ( transactionDriverControl == null ) { if ( transactionDriverControl == null ) {
@ -66,6 +76,7 @@ public class TransactionImpl implements TransactionImplementor {
} }
LOG.debug( "begin" ); LOG.debug( "begin" );
this.transactionDriverControl.begin(); this.transactionDriverControl.begin();
} }
@ -82,6 +93,7 @@ public class TransactionImpl implements TransactionImplementor {
} }
LOG.debug( "committing" ); LOG.debug( "committing" );
try { try {
internalGetTransactionDriverControl().commit(); internalGetTransactionDriverControl().commit();
} }
@ -100,8 +112,9 @@ public class TransactionImpl implements TransactionImplementor {
@Override @Override
public void rollback() { public void rollback() {
if ( jpaCompliance.isJpaTransactionComplianceEnabled() ) { if ( !isActive() ) {
if ( !isActive() ) { if ( jpaCompliance.isJpaTransactionComplianceEnabled() ) {
throw new IllegalStateException( throw new IllegalStateException(
"JPA compliance dictates throwing IllegalStateException when #rollback " + "JPA compliance dictates throwing IllegalStateException when #rollback " +
"is called on non-active transaction" "is called on non-active transaction"
@ -121,6 +134,7 @@ public class TransactionImpl implements TransactionImplementor {
} }
LOG.debug( "rolling back" ); LOG.debug( "rolling back" );
if ( status != TransactionStatus.FAILED_COMMIT || allowFailedCommitToPhysicallyRollback() ) { if ( status != TransactionStatus.FAILED_COMMIT || allowFailedCommitToPhysicallyRollback() ) {
internalGetTransactionDriverControl().rollback(); internalGetTransactionDriverControl().rollback();
} }
@ -136,7 +150,12 @@ public class TransactionImpl implements TransactionImplementor {
@Override @Override
public boolean isActive(boolean isMarkedForRollbackConsideredActive) { public boolean isActive(boolean isMarkedForRollbackConsideredActive) {
if ( transactionDriverControl == null ) { if ( transactionDriverControl == null ) {
transactionDriverControl = transactionCoordinator.getTransactionDriverControl(); if ( session.isOpen() ) {
transactionDriverControl = transactionCoordinator.getTransactionDriverControl();
}
else {
return false;
}
} }
return transactionDriverControl.isActive( isMarkedForRollbackConsideredActive ); return transactionDriverControl.isActive( isMarkedForRollbackConsideredActive );
} }
@ -144,7 +163,12 @@ public class TransactionImpl implements TransactionImplementor {
@Override @Override
public TransactionStatus getStatus() { public TransactionStatus getStatus() {
if ( transactionDriverControl == null ) { if ( transactionDriverControl == null ) {
transactionDriverControl = transactionCoordinator.getTransactionDriverControl(); if ( session.isOpen() ) {
transactionDriverControl = transactionCoordinator.getTransactionDriverControl();
}
else {
return TransactionStatus.NOT_ACTIVE;
}
} }
return transactionDriverControl.getStatus(); return transactionDriverControl.getStatus();
} }
@ -175,25 +199,29 @@ public class TransactionImpl implements TransactionImplementor {
@Override @Override
public void setRollbackOnly() { public void setRollbackOnly() {
// Since this is the JPA-defined one, we make sure the txn is active first if ( !isActive() ) {
// so long as compliance (JpaCompliance) has not been defined to disable // Since this is the JPA-defined one, we make sure the txn is active first
// that check - making this active more like Hibernate's #markRollbackOnly // so long as compliance (JpaCompliance) has not been defined to disable
if ( jpaCompliance.isJpaTransactionComplianceEnabled() ) { // that check - making this active more like Hibernate's #markRollbackOnly
if ( !isActive() ) { if ( jpaCompliance.isJpaTransactionComplianceEnabled() ) {
throw new IllegalStateException( throw new IllegalStateException(
"JPA compliance dictates throwing IllegalStateException when #setRollbackOnly " + "JPA compliance dictates throwing IllegalStateException when #setRollbackOnly " +
"is called on non-active transaction" "is called on non-active transaction"
); );
} }
else {
LOG.debug( "#setRollbackOnly called on a not-active transaction" );
}
}
else {
markRollbackOnly();
} }
markRollbackOnly();
} }
@Override @Override
public boolean getRollbackOnly() { public boolean getRollbackOnly() {
if ( jpaCompliance.isJpaTransactionComplianceEnabled() ) { if ( !isActive() ) {
if ( !isActive() ) { if ( jpaCompliance.isJpaTransactionComplianceEnabled() ) {
throw new IllegalStateException( throw new IllegalStateException(
"JPA compliance dictates throwing IllegalStateException when #getRollbackOnly " + "JPA compliance dictates throwing IllegalStateException when #getRollbackOnly " +
"is called on non-active transaction" "is called on non-active transaction"

View File

@ -80,7 +80,6 @@ import org.hibernate.resource.jdbc.spi.StatementInspector;
import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorImpl; import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorImpl;
import org.hibernate.resource.transaction.spi.TransactionCoordinator; import org.hibernate.resource.transaction.spi.TransactionCoordinator;
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder; import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
import org.hibernate.resource.transaction.spi.TransactionStatus;
import org.hibernate.type.Type; import org.hibernate.type.Type;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
@ -404,13 +403,12 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
@Override @Override
public Transaction accessTransaction() { public Transaction accessTransaction() {
if ( this.currentHibernateTransaction == null || this.currentHibernateTransaction.getStatus() != TransactionStatus.ACTIVE ) { if ( this.currentHibernateTransaction == null ) {
this.currentHibernateTransaction = new TransactionImpl( this.currentHibernateTransaction = new TransactionImpl(
getTransactionCoordinator(), getTransactionCoordinator(),
getExceptionConverter(), getExceptionConverter(),
getFactory().getSessionFactoryOptions().getJpaCompliance() this
); );
} }
if ( !isClosed() || (waitingForAutoClose && factory.isOpen()) ) { if ( !isClosed() || (waitingForAutoClose && factory.isOpen()) ) {
getTransactionCoordinator().pulse(); getTransactionCoordinator().pulse();