protected virtual SuspendedResourcesHolder Suspend(object transaction)
        {
            if (TransactionSynchronizationManager.IsSynchronizationActive())
            {
                var suspendedSynchronizations = DoSuspendSynchronization();
                try
                {
                    object suspendedResources = null;
                    if (transaction != null)
                    {
                        suspendedResources = DoSuspend(transaction);
                    }

                    var name = TransactionSynchronizationManager.GetCurrentTransactionName();
                    TransactionSynchronizationManager.SetCurrentTransactionName(null);
                    var readOnly = TransactionSynchronizationManager.IsCurrentTransactionReadOnly();
                    TransactionSynchronizationManager.SetCurrentTransactionReadOnly(false);
                    var isolationLevel = TransactionSynchronizationManager.GetCurrentTransactionIsolationLevel();
                    TransactionSynchronizationManager.SetCurrentTransactionIsolationLevel(null);
                    var wasActive = TransactionSynchronizationManager.IsActualTransactionActive();
                    TransactionSynchronizationManager.SetActualTransactionActive(false);
                    return(new SuspendedResourcesHolder(suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive));
                }
                catch (Exception)
                {
                    // doSuspend failed - original transaction is still active...
                    DoResumeSynchronization(suspendedSynchronizations);
                    throw;
                }
            }
            else if (transaction != null)
            {
                // Transaction active but no synchronization active.
                var suspendedResources = DoSuspend(transaction);
                return(new SuspendedResourcesHolder(suspendedResources));
            }
            else
            {
                // Neither transaction nor synchronization active.
                return(null);
            }
        }
        private ITransactionStatus HandleExistingTransaction(ITransactionDefinition definition, object transaction)
        {
            if (definition.PropagationBehavior == AbstractTransactionDefinition.PROPAGATION_NEVER)
            {
                throw new IllegalTransactionStateException(
                          "Existing transaction found for transaction marked with propagation 'never'");
            }

            if (definition.PropagationBehavior == AbstractTransactionDefinition.PROPAGATION_NOT_SUPPORTED)
            {
                _logger?.LogDebug("Suspending current transaction");
                var suspendedResources = Suspend(transaction);
                return(PrepareTransactionStatus(definition, null, false, TransactionSynchronization == SYNCHRONIZATION_ALWAYS, suspendedResources));
            }

            if (definition.PropagationBehavior == AbstractTransactionDefinition.PROPAGATION_REQUIRES_NEW)
            {
                _logger?.LogDebug("Suspending current transaction, creating new transaction with name [{name}]", definition.Name);
                var suspendedResources = Suspend(transaction);
                try
                {
                    var status = NewTransactionStatus(definition, transaction, true, TransactionSynchronization != SYNCHRONIZATION_NEVER, suspendedResources);
                    DoBegin(transaction, definition);
                    PrepareSynchronization(status, definition);
                    return(status);
                }
                catch (Exception ex)
                {
                    ResumeAfterBeginException(transaction, suspendedResources, ex);
                    throw;
                }
            }

            if (definition.PropagationBehavior == AbstractTransactionDefinition.PROPAGATION_NESTED)
            {
                if (!NestedTransactionAllowed)
                {
                    throw new NestedTransactionNotSupportedException(
                              "Transaction manager does not allow nested transactions by default - " +
                              "specify 'nestedTransactionAllowed' property with value 'true'");
                }

                _logger?.LogDebug("Creating nested transaction with name [{name}]", definition.Name);
                if (UseSavepointForNestedTransaction)
                {
                    // Create savepoint within existing Spring-managed transaction,
                    // through the SavepointManager API implemented by TransactionStatus.
                    // Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
                    var status = PrepareTransactionStatus(definition, transaction, false, false, null);
                    status.CreateAndHoldSavepoint();
                    return(status);
                }
                else
                {
                    // Nested transaction through nested begin and commit/rollback calls.
                    // Usually only for JTA: Spring synchronization might get activated here
                    // in case of a pre-existing JTA transaction.
                    var status = NewTransactionStatus(definition, transaction, true, TransactionSynchronization != SYNCHRONIZATION_NEVER, null);
                    DoBegin(transaction, definition);
                    PrepareSynchronization(status, definition);
                    return(status);
                }
            }

            // Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
            _logger?.LogDebug("Participating in existing transaction");
            if (ValidateExistingTransaction)
            {
                if (definition.IsolationLevel != AbstractTransactionDefinition.ISOLATION_DEFAULT)
                {
                    var currentIsolationLevel = TransactionSynchronizationManager.GetCurrentTransactionIsolationLevel();
                    if (currentIsolationLevel == null || currentIsolationLevel != definition.IsolationLevel)
                    {
                        throw new IllegalTransactionStateException("Participating transaction with definition [" +
                                                                   definition + "] specifies isolation level which is incompatible with existing transaction: ");
                    }
                }

                if (!definition.IsReadOnly && TransactionSynchronizationManager.IsCurrentTransactionReadOnly())
                {
                    throw new IllegalTransactionStateException("Participating transaction with definition [" +
                                                               definition + "] is not marked as read-only but existing transaction is");
                }
            }

            var newSynchronization = TransactionSynchronization != SYNCHRONIZATION_NEVER;

            return(PrepareTransactionStatus(definition, transaction, false, newSynchronization, null));
        }