Search in sources :

Example 1 with TransactionException

use of cn.taketoday.transaction.TransactionException in project today-infrastructure by TAKETODAY.

the class AbstractReactiveTransactionManager method getReactiveTransaction.

// ---------------------------------------------------------------------
// Implementation of ReactiveTransactionManager
// ---------------------------------------------------------------------
/**
 * This implementation handles propagation behavior. Delegates to
 * {@code doGetTransaction}, {@code isExistingTransaction}
 * and {@code doBegin}.
 *
 * @see #doGetTransaction
 * @see #isExistingTransaction
 * @see #doBegin
 */
@Override
public final Mono<ReactiveTransaction> getReactiveTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
    // Use defaults if no transaction definition given.
    TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
    return TransactionSynchronizationManager.forCurrentTransaction().flatMap(synchronizationManager -> {
        Object transaction = doGetTransaction(synchronizationManager);
        // Cache debug flag to avoid repeated checks.
        boolean debugEnabled = logger.isDebugEnabled();
        if (isExistingTransaction(transaction)) {
            // Existing transaction found -> check propagation behavior to find out how to behave.
            return handleExistingTransaction(synchronizationManager, def, transaction, debugEnabled);
        }
        // Check definition settings for new transaction.
        if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
            return Mono.error(new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout()));
        }
        // No existing transaction found -> check propagation behavior to find out how to proceed.
        if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
            return Mono.error(new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'"));
        } else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED || def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW || def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
            return TransactionContextManager.currentContext().map(TransactionSynchronizationManager::new).flatMap(nestedSynchronizationManager -> suspend(nestedSynchronizationManager, null).map(Optional::of).defaultIfEmpty(Optional.empty()).flatMap(suspendedResources -> {
                if (debugEnabled) {
                    logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
                }
                return Mono.defer(() -> {
                    GenericReactiveTransaction status = newReactiveTransaction(nestedSynchronizationManager, def, transaction, true, debugEnabled, suspendedResources.orElse(null));
                    return doBegin(nestedSynchronizationManager, transaction, def).doOnSuccess(ignore -> prepareSynchronization(nestedSynchronizationManager, status, def)).thenReturn(status);
                }).onErrorResume(ErrorPredicates.RUNTIME_OR_ERROR, ex -> resume(nestedSynchronizationManager, null, suspendedResources.orElse(null)).then(Mono.error(ex)));
            }));
        } else {
            // Create "empty" transaction: no actual transaction, but potentially synchronization.
            if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
                logger.warn("Custom isolation level specified but no actual transaction initiated; " + "isolation level will effectively be ignored: " + def);
            }
            return Mono.just(prepareReactiveTransaction(synchronizationManager, def, null, true, debugEnabled, null));
        }
    });
}
Also used : TransactionDefinition(cn.taketoday.transaction.TransactionDefinition) Serial(java.io.Serial) ReactiveTransaction(cn.taketoday.transaction.ReactiveTransaction) TransactionDefinition(cn.taketoday.transaction.TransactionDefinition) InvalidTimeoutException(cn.taketoday.transaction.InvalidTimeoutException) Predicate(java.util.function.Predicate) ObjectInputStream(java.io.ObjectInputStream) ReactiveTransactionManager(cn.taketoday.transaction.ReactiveTransactionManager) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) IOException(java.io.IOException) Mono(reactor.core.publisher.Mono) TransactionSuspensionNotSupportedException(cn.taketoday.transaction.TransactionSuspensionNotSupportedException) Serializable(java.io.Serializable) LoggerFactory(cn.taketoday.logging.LoggerFactory) Flux(reactor.core.publisher.Flux) List(java.util.List) Nullable(cn.taketoday.lang.Nullable) IllegalTransactionStateException(cn.taketoday.transaction.IllegalTransactionStateException) TransactionException(cn.taketoday.transaction.TransactionException) UnexpectedRollbackException(cn.taketoday.transaction.UnexpectedRollbackException) Logger(cn.taketoday.logging.Logger) Optional(java.util.Optional) InvalidTimeoutException(cn.taketoday.transaction.InvalidTimeoutException) Optional(java.util.Optional) IllegalTransactionStateException(cn.taketoday.transaction.IllegalTransactionStateException)

Example 2 with TransactionException

use of cn.taketoday.transaction.TransactionException in project today-infrastructure by TAKETODAY.

the class BeanFactoryTransactionTests method doTestGetsAreNotTransactional.

private void doTestGetsAreNotTransactional(final ITestBean testBean) {
    // Install facade
    PlatformTransactionManager ptm = mock(PlatformTransactionManager.class);
    PlatformTransactionManagerFacade.delegate = ptm;
    assertThat(testBean.getAge() == 666).as("Age should not be " + testBean.getAge()).isTrue();
    // Expect no methods
    verifyNoInteractions(ptm);
    // Install facade expecting a call
    final TransactionStatus ts = mock(TransactionStatus.class);
    ptm = new PlatformTransactionManager() {

        private boolean invoked;

        @Override
        public TransactionStatus getTransaction(@Nullable TransactionDefinition def) throws TransactionException {
            if (invoked) {
                throw new IllegalStateException("getTransaction should not get invoked more than once");
            }
            invoked = true;
            if (!(def.getName().contains(DerivedTestBean.class.getName()) && def.getName().contains("setAge"))) {
                throw new IllegalStateException("transaction name should contain class and method name: " + def.getName());
            }
            return ts;
        }

        @Override
        public void commit(TransactionStatus status) throws TransactionException {
            assertThat(status == ts).isTrue();
        }

        @Override
        public void rollback(TransactionStatus status) throws TransactionException {
            throw new IllegalStateException("rollback should not get invoked");
        }
    };
    PlatformTransactionManagerFacade.delegate = ptm;
    // TODO same as old age to avoid ordering effect for now
    int age = 666;
    testBean.setAge(age);
    assertThat(testBean.getAge() == age).isTrue();
}
Also used : TransactionDefinition(cn.taketoday.transaction.TransactionDefinition) TransactionException(cn.taketoday.transaction.TransactionException) TransactionStatus(cn.taketoday.transaction.TransactionStatus) DerivedTestBean(cn.taketoday.beans.testfixture.beans.DerivedTestBean) PlatformTransactionManager(cn.taketoday.transaction.PlatformTransactionManager)

Example 3 with TransactionException

use of cn.taketoday.transaction.TransactionException in project today-framework by TAKETODAY.

the class BeanFactoryTransactionTests method doTestGetsAreNotTransactional.

private void doTestGetsAreNotTransactional(final ITestBean testBean) {
    // Install facade
    PlatformTransactionManager ptm = mock(PlatformTransactionManager.class);
    PlatformTransactionManagerFacade.delegate = ptm;
    assertThat(testBean.getAge() == 666).as("Age should not be " + testBean.getAge()).isTrue();
    // Expect no methods
    verifyNoInteractions(ptm);
    // Install facade expecting a call
    final TransactionStatus ts = mock(TransactionStatus.class);
    ptm = new PlatformTransactionManager() {

        private boolean invoked;

        @Override
        public TransactionStatus getTransaction(@Nullable TransactionDefinition def) throws TransactionException {
            if (invoked) {
                throw new IllegalStateException("getTransaction should not get invoked more than once");
            }
            invoked = true;
            if (!(def.getName().contains(DerivedTestBean.class.getName()) && def.getName().contains("setAge"))) {
                throw new IllegalStateException("transaction name should contain class and method name: " + def.getName());
            }
            return ts;
        }

        @Override
        public void commit(TransactionStatus status) throws TransactionException {
            assertThat(status == ts).isTrue();
        }

        @Override
        public void rollback(TransactionStatus status) throws TransactionException {
            throw new IllegalStateException("rollback should not get invoked");
        }
    };
    PlatformTransactionManagerFacade.delegate = ptm;
    // TODO same as old age to avoid ordering effect for now
    int age = 666;
    testBean.setAge(age);
    assertThat(testBean.getAge() == age).isTrue();
}
Also used : TransactionDefinition(cn.taketoday.transaction.TransactionDefinition) TransactionException(cn.taketoday.transaction.TransactionException) TransactionStatus(cn.taketoday.transaction.TransactionStatus) DerivedTestBean(cn.taketoday.beans.testfixture.beans.DerivedTestBean) PlatformTransactionManager(cn.taketoday.transaction.PlatformTransactionManager)

Example 4 with TransactionException

use of cn.taketoday.transaction.TransactionException in project today-framework by TAKETODAY.

the class AbstractReactiveTransactionManager method processCommit.

/**
 * Process an actual commit.
 * Rollback-only flags have already been checked and applied.
 *
 * @param synchronizationManager the synchronization manager bound to the current transaction
 * @param status object representing the transaction
 * @throws TransactionException in case of commit failure
 */
private Mono<Void> processCommit(TransactionSynchronizationManager synchronizationManager, GenericReactiveTransaction status) throws TransactionException {
    AtomicBoolean beforeCompletionInvoked = new AtomicBoolean();
    Mono<Object> commit = prepareForCommit(synchronizationManager, status).then(triggerBeforeCommit(synchronizationManager, status)).then(triggerBeforeCompletion(synchronizationManager, status)).then(Mono.defer(() -> {
        beforeCompletionInvoked.set(true);
        if (status.isNewTransaction()) {
            if (status.isDebug()) {
                logger.debug("Initiating transaction commit");
            }
            return doCommit(synchronizationManager, status);
        }
        return Mono.empty();
    })).then(Mono.empty().onErrorResume(ex -> {
        Mono<Object> propagateException = Mono.error(ex);
        // Store result in a local variable in order to appease the
        // Eclipse compiler with regard to inferred generics.
        Mono<Object> result = propagateException;
        if (ErrorPredicates.UNEXPECTED_ROLLBACK.test(ex)) {
            result = triggerAfterCompletion(synchronizationManager, status, TransactionSynchronization.STATUS_ROLLED_BACK).then(propagateException);
        } else if (ErrorPredicates.TRANSACTION_EXCEPTION.test(ex)) {
            result = triggerAfterCompletion(synchronizationManager, status, TransactionSynchronization.STATUS_UNKNOWN).then(propagateException);
        } else if (ErrorPredicates.RUNTIME_OR_ERROR.test(ex)) {
            Mono<Void> mono;
            if (!beforeCompletionInvoked.get()) {
                mono = triggerBeforeCompletion(synchronizationManager, status);
            } else {
                mono = Mono.empty();
            }
            result = mono.then(doRollbackOnCommitException(synchronizationManager, status, ex)).then(propagateException);
        }
        return result;
    })).then(Mono.defer(() -> triggerAfterCommit(synchronizationManager, status).onErrorResume(ex -> triggerAfterCompletion(synchronizationManager, status, TransactionSynchronization.STATUS_COMMITTED).then(Mono.error(ex))).then(triggerAfterCompletion(synchronizationManager, status, TransactionSynchronization.STATUS_COMMITTED))));
    return commit.onErrorResume(ex -> cleanupAfterCompletion(synchronizationManager, status).then(Mono.error(ex))).then(cleanupAfterCompletion(synchronizationManager, status));
}
Also used : Serial(java.io.Serial) ReactiveTransaction(cn.taketoday.transaction.ReactiveTransaction) TransactionDefinition(cn.taketoday.transaction.TransactionDefinition) InvalidTimeoutException(cn.taketoday.transaction.InvalidTimeoutException) Predicate(java.util.function.Predicate) ObjectInputStream(java.io.ObjectInputStream) ReactiveTransactionManager(cn.taketoday.transaction.ReactiveTransactionManager) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) IOException(java.io.IOException) Mono(reactor.core.publisher.Mono) TransactionSuspensionNotSupportedException(cn.taketoday.transaction.TransactionSuspensionNotSupportedException) Serializable(java.io.Serializable) LoggerFactory(cn.taketoday.logging.LoggerFactory) Flux(reactor.core.publisher.Flux) List(java.util.List) Nullable(cn.taketoday.lang.Nullable) IllegalTransactionStateException(cn.taketoday.transaction.IllegalTransactionStateException) TransactionException(cn.taketoday.transaction.TransactionException) UnexpectedRollbackException(cn.taketoday.transaction.UnexpectedRollbackException) Logger(cn.taketoday.logging.Logger) Optional(java.util.Optional) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean)

Example 5 with TransactionException

use of cn.taketoday.transaction.TransactionException in project today-framework by TAKETODAY.

the class AbstractReactiveTransactionManager method getReactiveTransaction.

// ---------------------------------------------------------------------
// Implementation of ReactiveTransactionManager
// ---------------------------------------------------------------------
/**
 * This implementation handles propagation behavior. Delegates to
 * {@code doGetTransaction}, {@code isExistingTransaction}
 * and {@code doBegin}.
 *
 * @see #doGetTransaction
 * @see #isExistingTransaction
 * @see #doBegin
 */
@Override
public final Mono<ReactiveTransaction> getReactiveTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
    // Use defaults if no transaction definition given.
    TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
    return TransactionSynchronizationManager.forCurrentTransaction().flatMap(synchronizationManager -> {
        Object transaction = doGetTransaction(synchronizationManager);
        // Cache debug flag to avoid repeated checks.
        boolean debugEnabled = logger.isDebugEnabled();
        if (isExistingTransaction(transaction)) {
            // Existing transaction found -> check propagation behavior to find out how to behave.
            return handleExistingTransaction(synchronizationManager, def, transaction, debugEnabled);
        }
        // Check definition settings for new transaction.
        if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
            return Mono.error(new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout()));
        }
        // No existing transaction found -> check propagation behavior to find out how to proceed.
        if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
            return Mono.error(new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'"));
        } else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED || def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW || def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
            return TransactionContextManager.currentContext().map(TransactionSynchronizationManager::new).flatMap(nestedSynchronizationManager -> suspend(nestedSynchronizationManager, null).map(Optional::of).defaultIfEmpty(Optional.empty()).flatMap(suspendedResources -> {
                if (debugEnabled) {
                    logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
                }
                return Mono.defer(() -> {
                    GenericReactiveTransaction status = newReactiveTransaction(nestedSynchronizationManager, def, transaction, true, debugEnabled, suspendedResources.orElse(null));
                    return doBegin(nestedSynchronizationManager, transaction, def).doOnSuccess(ignore -> prepareSynchronization(nestedSynchronizationManager, status, def)).thenReturn(status);
                }).onErrorResume(ErrorPredicates.RUNTIME_OR_ERROR, ex -> resume(nestedSynchronizationManager, null, suspendedResources.orElse(null)).then(Mono.error(ex)));
            }));
        } else {
            // Create "empty" transaction: no actual transaction, but potentially synchronization.
            if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
                logger.warn("Custom isolation level specified but no actual transaction initiated; " + "isolation level will effectively be ignored: " + def);
            }
            return Mono.just(prepareReactiveTransaction(synchronizationManager, def, null, true, debugEnabled, null));
        }
    });
}
Also used : TransactionDefinition(cn.taketoday.transaction.TransactionDefinition) Serial(java.io.Serial) ReactiveTransaction(cn.taketoday.transaction.ReactiveTransaction) TransactionDefinition(cn.taketoday.transaction.TransactionDefinition) InvalidTimeoutException(cn.taketoday.transaction.InvalidTimeoutException) Predicate(java.util.function.Predicate) ObjectInputStream(java.io.ObjectInputStream) ReactiveTransactionManager(cn.taketoday.transaction.ReactiveTransactionManager) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) IOException(java.io.IOException) Mono(reactor.core.publisher.Mono) TransactionSuspensionNotSupportedException(cn.taketoday.transaction.TransactionSuspensionNotSupportedException) Serializable(java.io.Serializable) LoggerFactory(cn.taketoday.logging.LoggerFactory) Flux(reactor.core.publisher.Flux) List(java.util.List) Nullable(cn.taketoday.lang.Nullable) IllegalTransactionStateException(cn.taketoday.transaction.IllegalTransactionStateException) TransactionException(cn.taketoday.transaction.TransactionException) UnexpectedRollbackException(cn.taketoday.transaction.UnexpectedRollbackException) Logger(cn.taketoday.logging.Logger) Optional(java.util.Optional) InvalidTimeoutException(cn.taketoday.transaction.InvalidTimeoutException) Optional(java.util.Optional) IllegalTransactionStateException(cn.taketoday.transaction.IllegalTransactionStateException)

Aggregations

TransactionDefinition (cn.taketoday.transaction.TransactionDefinition)6 TransactionException (cn.taketoday.transaction.TransactionException)6 Nullable (cn.taketoday.lang.Nullable)4 Logger (cn.taketoday.logging.Logger)4 LoggerFactory (cn.taketoday.logging.LoggerFactory)4 IllegalTransactionStateException (cn.taketoday.transaction.IllegalTransactionStateException)4 InvalidTimeoutException (cn.taketoday.transaction.InvalidTimeoutException)4 ReactiveTransaction (cn.taketoday.transaction.ReactiveTransaction)4 ReactiveTransactionManager (cn.taketoday.transaction.ReactiveTransactionManager)4 TransactionSuspensionNotSupportedException (cn.taketoday.transaction.TransactionSuspensionNotSupportedException)4 UnexpectedRollbackException (cn.taketoday.transaction.UnexpectedRollbackException)4 IOException (java.io.IOException)4 ObjectInputStream (java.io.ObjectInputStream)4 Serial (java.io.Serial)4 Serializable (java.io.Serializable)4 List (java.util.List)4 Optional (java.util.Optional)4 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)4 Predicate (java.util.function.Predicate)4 Flux (reactor.core.publisher.Flux)4