improve exception messages and logging related to tx management
along with some minor aesthetic code cleanups
This commit is contained in:
parent
47f1a1207a
commit
453f0ff074
|
@ -69,9 +69,13 @@ public interface Transaction extends EntityTransaction {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to mark the underlying transaction for rollback only.
|
* Attempt to mark the underlying transaction for rollback only.
|
||||||
|
* <p>
|
||||||
|
* Unlike {@link #setRollbackOnly()}, which is specified by JPA
|
||||||
|
* to throw when the transaction is inactive, this operation may
|
||||||
|
* be called on an inactive transaction, in which case it has no
|
||||||
|
* effect.
|
||||||
|
*
|
||||||
|
* @see #setRollbackOnly()
|
||||||
*/
|
*/
|
||||||
default void markRollbackOnly() {
|
void markRollbackOnly();
|
||||||
setRollbackOnly();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ import org.hibernate.TransactionException;
|
||||||
import org.hibernate.engine.transaction.spi.TransactionImplementor;
|
import org.hibernate.engine.transaction.spi.TransactionImplementor;
|
||||||
import org.hibernate.internal.AbstractSharedSessionContract;
|
import org.hibernate.internal.AbstractSharedSessionContract;
|
||||||
import org.hibernate.internal.CoreLogging;
|
import org.hibernate.internal.CoreLogging;
|
||||||
import org.hibernate.jpa.spi.JpaCompliance;
|
|
||||||
import org.hibernate.resource.transaction.spi.TransactionCoordinator;
|
import org.hibernate.resource.transaction.spi.TransactionCoordinator;
|
||||||
import org.hibernate.resource.transaction.spi.TransactionStatus;
|
import org.hibernate.resource.transaction.spi.TransactionStatus;
|
||||||
|
|
||||||
|
@ -28,7 +27,7 @@ public class TransactionImpl implements TransactionImplementor {
|
||||||
private static final Logger LOG = CoreLogging.logger( TransactionImpl.class );
|
private static final Logger LOG = CoreLogging.logger( TransactionImpl.class );
|
||||||
|
|
||||||
private final TransactionCoordinator transactionCoordinator;
|
private final TransactionCoordinator transactionCoordinator;
|
||||||
private final JpaCompliance jpaCompliance;
|
private final boolean jpaCompliance;
|
||||||
private final AbstractSharedSessionContract session;
|
private final AbstractSharedSessionContract session;
|
||||||
|
|
||||||
private TransactionDriver transactionDriverControl;
|
private TransactionDriver transactionDriverControl;
|
||||||
|
@ -37,7 +36,9 @@ public class TransactionImpl implements TransactionImplementor {
|
||||||
TransactionCoordinator transactionCoordinator,
|
TransactionCoordinator transactionCoordinator,
|
||||||
AbstractSharedSessionContract session) {
|
AbstractSharedSessionContract session) {
|
||||||
this.transactionCoordinator = transactionCoordinator;
|
this.transactionCoordinator = transactionCoordinator;
|
||||||
this.jpaCompliance = session.getFactory().getSessionFactoryOptions().getJpaCompliance();
|
this.jpaCompliance =
|
||||||
|
session.getFactory().getSessionFactoryOptions().getJpaCompliance()
|
||||||
|
.isJpaTransactionComplianceEnabled();
|
||||||
this.session = session;
|
this.session = session;
|
||||||
|
|
||||||
if ( session.isOpen() && transactionCoordinator.isActive() ) {
|
if ( session.isOpen() && transactionCoordinator.isActive() ) {
|
||||||
|
@ -47,11 +48,8 @@ public class TransactionImpl implements TransactionImplementor {
|
||||||
LOG.debug( "TransactionImpl created on closed Session/EntityManager" );
|
LOG.debug( "TransactionImpl created on closed Session/EntityManager" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( LOG.isDebugEnabled() ) {
|
if ( LOG.isDebugEnabled() && jpaCompliance ) {
|
||||||
LOG.debugf(
|
LOG.debugf( "TransactionImpl created in JPA compliant mode" );
|
||||||
"On TransactionImpl creation, JpaCompliance#isJpaTransactionComplianceEnabled == %s",
|
|
||||||
jpaCompliance.isJpaTransactionComplianceEnabled()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,36 +63,31 @@ public class TransactionImpl implements TransactionImplementor {
|
||||||
transactionDriverControl = transactionCoordinator.getTransactionDriverControl();
|
transactionDriverControl = transactionCoordinator.getTransactionDriverControl();
|
||||||
}
|
}
|
||||||
|
|
||||||
// per-JPA
|
|
||||||
if ( isActive() ) {
|
if ( isActive() ) {
|
||||||
if ( jpaCompliance.isJpaTransactionComplianceEnabled()
|
if ( jpaCompliance ) {
|
||||||
|| !transactionCoordinator.getTransactionCoordinatorBuilder().isJta() ) {
|
throw new IllegalStateException( "Transaction already active (in JPA compliant mode)" );
|
||||||
throw new IllegalStateException( "Transaction already active" );
|
}
|
||||||
|
else if ( !transactionCoordinator.getTransactionCoordinatorBuilder().isJta() ) {
|
||||||
|
throw new IllegalStateException( "Resource-local transaction already active" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return;
|
LOG.debug( "begin transaction" );
|
||||||
|
transactionDriverControl.begin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG.debug( "begin" );
|
|
||||||
|
|
||||||
this.transactionDriverControl.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void commit() {
|
public void commit() {
|
||||||
if ( !isActive( true ) ) {
|
|
||||||
// allow MARKED_ROLLBACK to propagate through to transactionDriverControl
|
// allow MARKED_ROLLBACK to propagate through to transactionDriverControl
|
||||||
// the boolean passed to isActive indicates whether MARKED_ROLLBACK should be
|
// the boolean passed to isActive indicates whether MARKED_ROLLBACK should
|
||||||
// considered active
|
// be considered active
|
||||||
//
|
if ( !isActive( true ) ) {
|
||||||
// essentially here we have a transaction that is not active and
|
// we have a transaction that is inactive and has not been marked for rollback only
|
||||||
// has not been marked for rollback only
|
|
||||||
throw new IllegalStateException( "Transaction not successfully started" );
|
throw new IllegalStateException( "Transaction not successfully started" );
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
LOG.debug( "committing" );
|
LOG.debug( "committing transaction" );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
internalGetTransactionDriverControl().commit();
|
internalGetTransactionDriverControl().commit();
|
||||||
}
|
}
|
||||||
|
@ -102,41 +95,34 @@ public class TransactionImpl implements TransactionImplementor {
|
||||||
throw session.getExceptionConverter().convertCommitException( e );
|
throw session.getExceptionConverter().convertCommitException( e );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public TransactionDriver internalGetTransactionDriverControl() {
|
public TransactionDriver internalGetTransactionDriverControl() {
|
||||||
// NOTE here to help be a more descriptive NullPointerException
|
// NOTE here to help be a more descriptive NullPointerException
|
||||||
if ( this.transactionDriverControl == null ) {
|
if ( transactionDriverControl == null ) {
|
||||||
throw new IllegalStateException( "Transaction was not properly begun/started" );
|
throw new IllegalStateException( "Transaction was not properly begun/started" );
|
||||||
}
|
}
|
||||||
return this.transactionDriverControl;
|
else {
|
||||||
|
return transactionDriverControl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void rollback() {
|
public void rollback() {
|
||||||
if ( !isActive() ) {
|
if ( !isActive() && jpaCompliance ) {
|
||||||
if ( jpaCompliance.isJpaTransactionComplianceEnabled() ) {
|
throw new IllegalStateException( "rollback() called on inactive transaction (in JPA compliant mode)" );
|
||||||
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"JPA compliance dictates throwing IllegalStateException when #rollback " +
|
|
||||||
"is called on non-active transaction"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TransactionStatus status = getStatus();
|
final TransactionStatus status = getStatus();
|
||||||
if ( status == TransactionStatus.ROLLED_BACK || status == TransactionStatus.NOT_ACTIVE ) {
|
if ( status == TransactionStatus.ROLLED_BACK || status == TransactionStatus.NOT_ACTIVE ) {
|
||||||
// Allow rollback() calls on completed transactions, just no-op.
|
// allow rollback() on completed transaction as noop
|
||||||
LOG.debug( "rollback() called on an inactive transaction" );
|
LOG.debug( "rollback() called on an inactive transaction" );
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else if ( !status.canRollback() ) {
|
||||||
if ( !status.canRollback() ) {
|
|
||||||
throw new TransactionException( "Cannot roll back transaction in current status [" + status.name() + "]" );
|
throw new TransactionException( "Cannot roll back transaction in current status [" + status.name() + "]" );
|
||||||
}
|
}
|
||||||
|
else if ( status != TransactionStatus.FAILED_COMMIT || allowFailedCommitToPhysicallyRollback() ) {
|
||||||
LOG.debug( "rolling back" );
|
LOG.debug( "rolling back transaction" );
|
||||||
|
|
||||||
if ( status != TransactionStatus.FAILED_COMMIT || allowFailedCommitToPhysicallyRollback() ) {
|
|
||||||
internalGetTransactionDriverControl().rollback();
|
internalGetTransactionDriverControl().rollback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,55 +162,50 @@ public class TransactionImpl implements TransactionImplementor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerSynchronization(Synchronization synchronization) throws HibernateException {
|
public void registerSynchronization(Synchronization synchronization) throws HibernateException {
|
||||||
this.transactionCoordinator.getLocalSynchronizations().registerSynchronization( synchronization );
|
transactionCoordinator.getLocalSynchronizations().registerSynchronization( synchronization );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTimeout(int seconds) {
|
public void setTimeout(int seconds) {
|
||||||
this.transactionCoordinator.setTimeOut( seconds );
|
transactionCoordinator.setTimeOut( seconds );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTimeout(@Nullable Integer seconds) {
|
public void setTimeout(@Nullable Integer seconds) {
|
||||||
this.transactionCoordinator.setTimeOut( seconds == null ? -1 : seconds );
|
transactionCoordinator.setTimeOut( seconds == null ? -1 : seconds );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable Integer getTimeout() {
|
public @Nullable Integer getTimeout() {
|
||||||
final int timeOut = this.transactionCoordinator.getTimeOut();
|
final int timeout = transactionCoordinator.getTimeOut();
|
||||||
if ( timeOut == -1 ) {
|
return timeout == -1 ? null : timeout;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return timeOut;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void markRollbackOnly() {
|
public void markRollbackOnly() {
|
||||||
// this is the Hibernate-specific API, whereas #setRollbackOnly is the
|
// this is the Hibernate-specific API, whereas setRollbackOnly is the
|
||||||
// JPA-defined API. In our opinion it is much more user-friendly to
|
// JPA-defined API. In our opinion it is much more user-friendly to
|
||||||
// always allow user/integration to indicate that the transaction
|
// always allow user/integration to indicate that the transaction
|
||||||
// should not be allowed to commit.
|
// should not be allowed to commit.
|
||||||
//
|
//
|
||||||
// However.. should only "do something" on an active transaction
|
|
||||||
if ( isActive() ) {
|
if ( isActive() ) {
|
||||||
internalGetTransactionDriverControl().markRollbackOnly();
|
internalGetTransactionDriverControl().markRollbackOnly();
|
||||||
}
|
}
|
||||||
|
// else noop for an inactive transaction
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setRollbackOnly() {
|
public void setRollbackOnly() {
|
||||||
if ( !isActive() ) {
|
if ( !isActive() ) {
|
||||||
// Since this is the JPA-defined one, we make sure the txn is active first
|
if ( jpaCompliance ) {
|
||||||
// so long as compliance (JpaCompliance) has not been defined to disable
|
// This is the JPA-defined version of this operation,
|
||||||
// that check - making this active more like Hibernate's #markRollbackOnly
|
// so we must check that the transaction is active
|
||||||
if ( jpaCompliance.isJpaTransactionComplianceEnabled() ) {
|
throw new IllegalStateException( "setRollbackOnly() called on inactive transaction (in JPA compliant mode)" );
|
||||||
throw new IllegalStateException(
|
|
||||||
"JPA compliance dictates throwing IllegalStateException when #setRollbackOnly " +
|
|
||||||
"is called on non-active transaction"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG.debug( "#setRollbackOnly called on a not-active transaction" );
|
// JpaCompliance disables the check, so this method
|
||||||
|
// is equivalent our native markRollbackOnly()
|
||||||
|
LOG.debug( "setRollbackOnly() called on a inactive transaction" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -234,17 +215,13 @@ public class TransactionImpl implements TransactionImplementor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getRollbackOnly() {
|
public boolean getRollbackOnly() {
|
||||||
if ( !isActive() ) {
|
if ( jpaCompliance && !isActive() ) {
|
||||||
if ( jpaCompliance.isJpaTransactionComplianceEnabled() ) {
|
throw new IllegalStateException( "getRollbackOnly() called on inactive transaction (in JPA compliant mode)" );
|
||||||
throw new IllegalStateException(
|
|
||||||
"JPA compliance dictates throwing IllegalStateException when #getRollbackOnly " +
|
|
||||||
"is called on non-active transaction"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
|
|
||||||
return getStatus() == TransactionStatus.MARKED_ROLLBACK;
|
return getStatus() == TransactionStatus.MARKED_ROLLBACK;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected boolean allowFailedCommitToPhysicallyRollback() {
|
protected boolean allowFailedCommitToPhysicallyRollback() {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -63,7 +63,7 @@ public class ExceptionConverterImpl implements ExceptionConverter {
|
||||||
catch (Exception re) {
|
catch (Exception re) {
|
||||||
//swallow
|
//swallow
|
||||||
}
|
}
|
||||||
return new RollbackException( "Error while committing the transaction",
|
return new RollbackException( "Error while committing the transaction [" + exception.getMessage() + "]",
|
||||||
exception instanceof HibernateException hibernateException
|
exception instanceof HibernateException hibernateException
|
||||||
? convert( hibernateException )
|
? convert( hibernateException )
|
||||||
: exception );
|
: exception );
|
||||||
|
|
|
@ -358,18 +358,16 @@ public final class FastSessionServices {
|
||||||
|
|
||||||
private static CacheRetrieveMode determineCacheRetrieveMode(Map<String, Object> settings) {
|
private static CacheRetrieveMode determineCacheRetrieveMode(Map<String, Object> settings) {
|
||||||
final CacheRetrieveMode cacheRetrieveMode = (CacheRetrieveMode) settings.get( JPA_SHARED_CACHE_RETRIEVE_MODE );
|
final CacheRetrieveMode cacheRetrieveMode = (CacheRetrieveMode) settings.get( JPA_SHARED_CACHE_RETRIEVE_MODE );
|
||||||
if ( cacheRetrieveMode == null ) {
|
return cacheRetrieveMode == null
|
||||||
return (CacheRetrieveMode) settings.get( JAKARTA_SHARED_CACHE_RETRIEVE_MODE );
|
? (CacheRetrieveMode) settings.get( JAKARTA_SHARED_CACHE_RETRIEVE_MODE )
|
||||||
}
|
: cacheRetrieveMode;
|
||||||
return cacheRetrieveMode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CacheStoreMode determineCacheStoreMode(Map<String, Object> settings) {
|
private static CacheStoreMode determineCacheStoreMode(Map<String, Object> settings) {
|
||||||
final CacheStoreMode cacheStoreMode = (CacheStoreMode) settings.get( JPA_SHARED_CACHE_STORE_MODE );
|
final CacheStoreMode cacheStoreMode = (CacheStoreMode) settings.get( JPA_SHARED_CACHE_STORE_MODE );
|
||||||
if ( cacheStoreMode == null ) {
|
return cacheStoreMode == null
|
||||||
return ( CacheStoreMode ) settings.get( JAKARTA_SHARED_CACHE_STORE_MODE );
|
? (CacheStoreMode) settings.get( JAKARTA_SHARED_CACHE_STORE_MODE )
|
||||||
}
|
: cacheStoreMode;
|
||||||
return cacheStoreMode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public JdbcValuesMappingProducerProvider getJdbcValuesMappingProducerProvider() {
|
public JdbcValuesMappingProducerProvider getJdbcValuesMappingProducerProvider() {
|
||||||
|
|
|
@ -169,15 +169,15 @@ public class MutableJpaComplianceImpl implements MutableJpaCompliance {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JpaCompliance immutableCopy() {
|
public JpaCompliance immutableCopy() {
|
||||||
JpaComplianceImpl.JpaComplianceBuilder builder = new JpaComplianceImpl.JpaComplianceBuilder();
|
return new JpaComplianceImpl.JpaComplianceBuilder()
|
||||||
builder = builder.setProxyCompliance( proxyCompliance )
|
.setProxyCompliance( proxyCompliance )
|
||||||
.setOrderByMappingCompliance( orderByMappingCompliance )
|
.setOrderByMappingCompliance( orderByMappingCompliance )
|
||||||
.setGlobalGeneratorNameCompliance( generatorNameScopeCompliance )
|
.setGlobalGeneratorNameCompliance( generatorNameScopeCompliance )
|
||||||
.setQueryCompliance( queryCompliance )
|
.setQueryCompliance( queryCompliance )
|
||||||
.setTransactionCompliance( transactionCompliance )
|
.setTransactionCompliance( transactionCompliance )
|
||||||
.setClosedCompliance( closedCompliance )
|
.setClosedCompliance( closedCompliance )
|
||||||
.setCachingCompliance( cachingCompliance )
|
.setCachingCompliance( cachingCompliance )
|
||||||
.setLoadByIdCompliance( loadByIdCompliance );
|
.setLoadByIdCompliance( loadByIdCompliance )
|
||||||
return builder.createJpaCompliance();
|
.createJpaCompliance();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,7 +148,6 @@ public class JdbcResourceLocalTransactionCoordinatorImpl implements TransactionC
|
||||||
transactionCoordinatorOwner.setTransactionTimeOut( timeOut );
|
transactionCoordinatorOwner.setTransactionTimeOut( timeOut );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// report entering into a "transactional context"
|
// report entering into a "transactional context"
|
||||||
transactionCoordinatorOwner.startTransactionBoundary();
|
transactionCoordinatorOwner.startTransactionBoundary();
|
||||||
|
|
||||||
|
@ -184,7 +183,6 @@ public class JdbcResourceLocalTransactionCoordinatorImpl implements TransactionC
|
||||||
log.tracef( "ResourceLocalTransactionCoordinatorImpl#afterCompletionCallback(%s)", successful );
|
log.tracef( "ResourceLocalTransactionCoordinatorImpl#afterCompletionCallback(%s)", successful );
|
||||||
final int statusToSend = successful ? Status.STATUS_COMMITTED : Status.STATUS_UNKNOWN;
|
final int statusToSend = successful ? Status.STATUS_COMMITTED : Status.STATUS_UNKNOWN;
|
||||||
synchronizationRegistry.notifySynchronizationsAfterTransactionCompletion( statusToSend );
|
synchronizationRegistry.notifySynchronizationsAfterTransactionCompletion( statusToSend );
|
||||||
|
|
||||||
transactionCoordinatorOwner.afterTransactionCompletion( successful, false );
|
transactionCoordinatorOwner.afterTransactionCompletion( successful, false );
|
||||||
for ( TransactionObserver observer : observers() ) {
|
for ( TransactionObserver observer : observers() ) {
|
||||||
observer.afterCompletion( successful, false );
|
observer.afterCompletion( successful, false );
|
||||||
|
@ -216,7 +214,6 @@ public class JdbcResourceLocalTransactionCoordinatorImpl implements TransactionC
|
||||||
private boolean rollbackOnly = false;
|
private boolean rollbackOnly = false;
|
||||||
|
|
||||||
public TransactionDriverControlImpl(JdbcResourceTransaction jdbcResourceTransaction) {
|
public TransactionDriverControlImpl(JdbcResourceTransaction jdbcResourceTransaction) {
|
||||||
super();
|
|
||||||
this.jdbcResourceTransaction = jdbcResourceTransaction;
|
this.jdbcResourceTransaction = jdbcResourceTransaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,7 +224,6 @@ public class JdbcResourceLocalTransactionCoordinatorImpl implements TransactionC
|
||||||
@Override
|
@Override
|
||||||
public void begin() {
|
public void begin() {
|
||||||
errorIfInvalid();
|
errorIfInvalid();
|
||||||
|
|
||||||
jdbcResourceTransaction.begin();
|
jdbcResourceTransaction.begin();
|
||||||
JdbcResourceLocalTransactionCoordinatorImpl.this.afterBeginCallback();
|
JdbcResourceLocalTransactionCoordinatorImpl.this.afterBeginCallback();
|
||||||
}
|
}
|
||||||
|
@ -242,31 +238,14 @@ public class JdbcResourceLocalTransactionCoordinatorImpl implements TransactionC
|
||||||
public void commit() {
|
public void commit() {
|
||||||
try {
|
try {
|
||||||
if ( rollbackOnly ) {
|
if ( rollbackOnly ) {
|
||||||
log.debug( "On commit, transaction was marked for roll-back only, rolling back" );
|
commitRollbackOnly();
|
||||||
|
|
||||||
try {
|
|
||||||
rollback();
|
|
||||||
|
|
||||||
if ( jpaCompliance.isJpaTransactionComplianceEnabled() ) {
|
|
||||||
log.debug( "Throwing RollbackException on roll-back of transaction marked rollback-only on commit" );
|
|
||||||
throw new RollbackException( "Transaction was marked for rollback-only" );
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch (RollbackException e) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
catch (RuntimeException e) {
|
|
||||||
log.debug( "Encountered failure rolling back failed commit", e );
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JdbcResourceLocalTransactionCoordinatorImpl.this.beforeCompletionCallback();
|
JdbcResourceLocalTransactionCoordinatorImpl.this.beforeCompletionCallback();
|
||||||
jdbcResourceTransaction.commit();
|
jdbcResourceTransaction.commit();
|
||||||
JdbcResourceLocalTransactionCoordinatorImpl.this.afterCompletionCallback( true );
|
JdbcResourceLocalTransactionCoordinatorImpl.this.afterCompletionCallback( true );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (RollbackException e) {
|
catch (RollbackException e) {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
@ -281,6 +260,23 @@ public class JdbcResourceLocalTransactionCoordinatorImpl implements TransactionC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void commitRollbackOnly() {
|
||||||
|
log.debug( "On commit, transaction was marked for roll-back only, rolling back" );
|
||||||
|
try {
|
||||||
|
rollback();
|
||||||
|
if ( jpaCompliance.isJpaTransactionComplianceEnabled() ) {
|
||||||
|
throw new RollbackException( "Transaction was marked for rollback-only" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (RollbackException e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
catch (RuntimeException e) {
|
||||||
|
log.debug( "Encountered failure rolling back failed commit", e );
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void rollback() {
|
public void rollback() {
|
||||||
try {
|
try {
|
||||||
|
@ -292,8 +288,6 @@ public class JdbcResourceLocalTransactionCoordinatorImpl implements TransactionC
|
||||||
finally {
|
finally {
|
||||||
rollbackOnly = false;
|
rollbackOnly = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// no-op otherwise.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -305,12 +299,9 @@ public class JdbcResourceLocalTransactionCoordinatorImpl implements TransactionC
|
||||||
public void markRollbackOnly() {
|
public void markRollbackOnly() {
|
||||||
if ( getStatus() != TransactionStatus.ROLLED_BACK ) {
|
if ( getStatus() != TransactionStatus.ROLLED_BACK ) {
|
||||||
if ( log.isDebugEnabled() ) {
|
if ( log.isDebugEnabled() ) {
|
||||||
log.debug(
|
log.debug( "JDBC transaction marked for rollback-only (exception provided for stack trace)",
|
||||||
"JDBC transaction marked for rollback-only (exception provided for stack trace)",
|
new Exception( "exception just for purpose of providing stack trace" ) );
|
||||||
new Exception( "exception just for purpose of providing stack trace" )
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rollbackOnly = true;
|
rollbackOnly = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,56 +136,47 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void pulse() {
|
public void pulse() {
|
||||||
if ( !autoJoinTransactions ) {
|
if ( autoJoinTransactions && !synchronizationRegistered ) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( synchronizationRegistered ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can we register a synchronization according to the JtaPlatform?
|
// Can we register a synchronization according to the JtaPlatform?
|
||||||
if ( !jtaPlatform.canRegisterSynchronization() ) {
|
if ( !jtaPlatform.canRegisterSynchronization() ) {
|
||||||
log.trace( "JTA platform says we cannot currently register synchronization; skipping" );
|
log.trace( "JTA platform says we cannot currently register synchronization; skipping" );
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
joinJtaTransaction();
|
joinJtaTransaction();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Join to the JTA transaction. Note that the underlying meaning of joining in JTA environments is to register the
|
* Join to the JTA transaction. Note that the underlying meaning of joining in JTA environments is to register the
|
||||||
* RegisteredSynchronization with the JTA system
|
* RegisteredSynchronization with the JTA system
|
||||||
*/
|
*/
|
||||||
private void joinJtaTransaction() {
|
private void joinJtaTransaction() {
|
||||||
if ( synchronizationRegistered ) {
|
if ( !synchronizationRegistered ) {
|
||||||
return;
|
jtaPlatform.registerSynchronization(
|
||||||
}
|
new RegisteredSynchronization( getSynchronizationCallbackCoordinator() ) );
|
||||||
|
|
||||||
jtaPlatform.registerSynchronization( new RegisteredSynchronization( getSynchronizationCallbackCoordinator() ) );
|
|
||||||
getSynchronizationCallbackCoordinator().synchronizationRegistered();
|
getSynchronizationCallbackCoordinator().synchronizationRegistered();
|
||||||
synchronizationRegistered = true;
|
synchronizationRegistered = true;
|
||||||
log.debug( "Hibernate RegisteredSynchronization successfully registered with JTA platform" );
|
log.debug( "Hibernate RegisteredSynchronization successfully registered with JTA platform" );
|
||||||
|
|
||||||
// report entering into a "transactional context"
|
// report entering into a "transactional context"
|
||||||
getTransactionCoordinatorOwner().startTransactionBoundary();
|
getTransactionCoordinatorOwner().startTransactionBoundary();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void explicitJoin() {
|
public void explicitJoin() {
|
||||||
if ( synchronizationRegistered ) {
|
if ( synchronizationRegistered ) {
|
||||||
log.debug( "JTA transaction was already joined (RegisteredSynchronization already registered)" );
|
log.debug( "JTA transaction was already joined (RegisteredSynchronization already registered)" );
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
if ( getTransactionDriverControl().getStatus() != ACTIVE ) {
|
if ( getTransactionDriverControl().getStatus() != ACTIVE ) {
|
||||||
throw new TransactionRequiredForJoinException(
|
throw new TransactionRequiredForJoinException(
|
||||||
"Explicitly joining a JTA transaction requires a JTA transaction be currently active"
|
"Explicitly joining a JTA transaction requires a JTA transaction be currently active"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
joinJtaTransaction();
|
joinJtaTransaction();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isJoined() {
|
public boolean isJoined() {
|
||||||
|
@ -204,7 +195,7 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
|
||||||
}
|
}
|
||||||
|
|
||||||
public TransactionCoordinatorOwner getTransactionCoordinatorOwner(){
|
public TransactionCoordinatorOwner getTransactionCoordinatorOwner(){
|
||||||
return this.transactionCoordinatorOwner;
|
return transactionCoordinatorOwner;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -221,39 +212,44 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
|
||||||
}
|
}
|
||||||
|
|
||||||
private TransactionDriverControlImpl makePhysicalTransactionDelegate() {
|
private TransactionDriverControlImpl makePhysicalTransactionDelegate() {
|
||||||
JtaTransactionAdapter adapter;
|
final JtaTransactionAdapter adapter =
|
||||||
|
preferUserTransactions
|
||||||
if ( preferUserTransactions ) {
|
? getTransactionAdapterPreferringUserTransaction()
|
||||||
adapter = makeUserTransactionAdapter();
|
: getTransactionAdapterPreferringTransactionManager();
|
||||||
|
|
||||||
if ( adapter == null ) {
|
|
||||||
log.debug( "Unable to access UserTransaction, attempting to use TransactionManager instead" );
|
|
||||||
adapter = makeTransactionManagerAdapter();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
adapter = makeTransactionManagerAdapter();
|
|
||||||
|
|
||||||
if ( adapter == null ) {
|
|
||||||
log.debug( "Unable to access TransactionManager, attempting to use UserTransaction instead" );
|
|
||||||
adapter = makeUserTransactionAdapter();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( adapter == null ) {
|
if ( adapter == null ) {
|
||||||
throw new JtaPlatformInaccessibleException(
|
throw new JtaPlatformInaccessibleException(
|
||||||
"Unable to access TransactionManager or UserTransaction to make physical transaction delegate"
|
"Unable to access TransactionManager or UserTransaction to make physical transaction delegate"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
return new TransactionDriverControlImpl( adapter );
|
return new TransactionDriverControlImpl( adapter );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private JtaTransactionAdapter getTransactionAdapterPreferringTransactionManager() {
|
||||||
|
final JtaTransactionAdapter adapter = makeTransactionManagerAdapter();
|
||||||
|
if ( adapter == null ) {
|
||||||
|
log.debug( "Unable to access TransactionManager, attempting to use UserTransaction instead" );
|
||||||
|
return makeUserTransactionAdapter();
|
||||||
|
}
|
||||||
|
return adapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JtaTransactionAdapter getTransactionAdapterPreferringUserTransaction() {
|
||||||
|
final JtaTransactionAdapter adapter = makeUserTransactionAdapter();
|
||||||
|
if ( adapter == null ) {
|
||||||
|
log.debug( "Unable to access UserTransaction, attempting to use TransactionManager instead" );
|
||||||
|
return makeTransactionManagerAdapter();
|
||||||
|
}
|
||||||
|
return adapter;
|
||||||
|
}
|
||||||
|
|
||||||
private JtaTransactionAdapter makeUserTransactionAdapter() {
|
private JtaTransactionAdapter makeUserTransactionAdapter() {
|
||||||
try {
|
try {
|
||||||
final UserTransaction userTransaction = jtaPlatform.retrieveUserTransaction();
|
final UserTransaction userTransaction = jtaPlatform.retrieveUserTransaction();
|
||||||
if ( userTransaction == null ) {
|
if ( userTransaction == null ) {
|
||||||
log.debug( "JtaPlatform#retrieveUserTransaction returned null" );
|
log.debug( "JtaPlatform#retrieveUserTransaction returned null" );
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return new JtaTransactionAdapterUserTransactionImpl( userTransaction );
|
return new JtaTransactionAdapterUserTransactionImpl( userTransaction );
|
||||||
|
@ -261,16 +257,16 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
|
||||||
}
|
}
|
||||||
catch ( Exception exception ) {
|
catch ( Exception exception ) {
|
||||||
log.debugf( "JtaPlatform#retrieveUserTransaction threw an exception [%s]", exception.getMessage() );
|
log.debugf( "JtaPlatform#retrieveUserTransaction threw an exception [%s]", exception.getMessage() );
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private JtaTransactionAdapter makeTransactionManagerAdapter() {
|
private JtaTransactionAdapter makeTransactionManagerAdapter() {
|
||||||
try {
|
try {
|
||||||
final TransactionManager transactionManager = jtaPlatform.retrieveTransactionManager();
|
final TransactionManager transactionManager = jtaPlatform.retrieveTransactionManager();
|
||||||
if ( transactionManager == null ) {
|
if ( transactionManager == null ) {
|
||||||
log.debug( "JtaPlatform#retrieveTransactionManager returned null" );
|
log.debug( "JtaPlatform#retrieveTransactionManager returned null" );
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return new JtaTransactionAdapterTransactionManagerImpl( transactionManager );
|
return new JtaTransactionAdapterTransactionManagerImpl( transactionManager );
|
||||||
|
@ -278,10 +274,9 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
|
||||||
}
|
}
|
||||||
catch ( Exception exception ) {
|
catch ( Exception exception ) {
|
||||||
log.debugf( "JtaPlatform#retrieveTransactionManager threw an exception [%s]", exception.getMessage() );
|
log.debugf( "JtaPlatform#retrieveTransactionManager threw an exception [%s]", exception.getMessage() );
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SynchronizationRegistry getLocalSynchronizations() {
|
public SynchronizationRegistry getLocalSynchronizations() {
|
||||||
|
@ -399,7 +394,6 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
|
||||||
@Override
|
@Override
|
||||||
public void begin() {
|
public void begin() {
|
||||||
errorIfInvalid();
|
errorIfInvalid();
|
||||||
|
|
||||||
jtaTransactionAdapter.begin();
|
jtaTransactionAdapter.begin();
|
||||||
JtaTransactionCoordinatorImpl.this.joinJtaTransaction();
|
JtaTransactionCoordinatorImpl.this.joinJtaTransaction();
|
||||||
}
|
}
|
||||||
|
@ -414,7 +408,6 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
|
||||||
public void commit() {
|
public void commit() {
|
||||||
errorIfInvalid();
|
errorIfInvalid();
|
||||||
getTransactionCoordinatorOwner().flushBeforeTransactionCompletion();
|
getTransactionCoordinatorOwner().flushBeforeTransactionCompletion();
|
||||||
|
|
||||||
// we don't have to perform any before/after completion processing here. We leave that for
|
// we don't have to perform any before/after completion processing here. We leave that for
|
||||||
// the Synchronization callbacks
|
// the Synchronization callbacks
|
||||||
jtaTransactionAdapter.commit();
|
jtaTransactionAdapter.commit();
|
||||||
|
@ -423,7 +416,6 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
|
||||||
@Override
|
@Override
|
||||||
public void rollback() {
|
public void rollback() {
|
||||||
errorIfInvalid();
|
errorIfInvalid();
|
||||||
|
|
||||||
// we don't have to perform any after completion processing here. We leave that for
|
// we don't have to perform any after completion processing here. We leave that for
|
||||||
// the Synchronization callbacks
|
// the Synchronization callbacks
|
||||||
jtaTransactionAdapter.rollback();
|
jtaTransactionAdapter.rollback();
|
||||||
|
|
|
@ -40,6 +40,8 @@ public interface TransactionCoordinatorBuilder extends Service {
|
||||||
PhysicalConnectionHandlingMode getDefaultConnectionHandlingMode();
|
PhysicalConnectionHandlingMode getDefaultConnectionHandlingMode();
|
||||||
|
|
||||||
default DdlTransactionIsolator buildDdlTransactionIsolator(JdbcContext jdbcContext) {
|
default DdlTransactionIsolator buildDdlTransactionIsolator(JdbcContext jdbcContext) {
|
||||||
return isJta() ? new DdlTransactionIsolatorJtaImpl( jdbcContext ) : new DdlTransactionIsolatorNonJtaImpl( jdbcContext );
|
return isJta()
|
||||||
|
? new DdlTransactionIsolatorJtaImpl( jdbcContext )
|
||||||
|
: new DdlTransactionIsolatorNonJtaImpl( jdbcContext );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,7 +74,7 @@ public class TransactionCommitFailureTest {
|
||||||
em.getTransaction().commit();
|
em.getTransaction().commit();
|
||||||
}
|
}
|
||||||
catch (RollbackException e) {
|
catch (RollbackException e) {
|
||||||
assertEquals( COMMIT_FAILURE, e.getLocalizedMessage() );
|
assertTrue( e.getLocalizedMessage().startsWith( COMMIT_FAILURE ) );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
if ( em.getTransaction() != null && em.getTransaction().isActive() ) {
|
if ( em.getTransaction() != null && em.getTransaction().isActive() ) {
|
||||||
|
|
Loading…
Reference in New Issue