improve exception messages and logging related to tx management

along with some minor aesthetic code cleanups
This commit is contained in:
Gavin King 2024-11-20 10:50:01 +01:00
parent 47f1a1207a
commit 453f0ff074
11 changed files with 161 additions and 196 deletions

View File

@ -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();
}
} }

View File

@ -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;

View File

@ -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 );

View File

@ -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() {

View File

@ -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();
} }
} }

View File

@ -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;
} }
} }

View File

@ -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();

View File

@ -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 );
} }
} }

View File

@ -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() ) {