== the propagation matrix ==

Each inner method is called twice: once from a @Transactional caller and once from a
plain one. 'active' is TransactionSynchronizationManager.isActualTransactionActive();
'name' is the transaction's name, which is how you tell JOINING from STARTING -- a
joining method reports the OUTER method's name.

  PROPAGATION    CALLER                   ACTIVE   TRANSACTION NAME / OUTCOME
  ----------------------------------------------------------------------------
  REQUIRED       inside @Transactional    True     inTransaction
  REQUIRED       no transaction           True     required

  REQUIRES_NEW   inside @Transactional    True     requiresNew
  REQUIRES_NEW   no transaction           True     requiresNew

  NESTED         inside @Transactional    --       NestedTransactionNotSupportedException
  NESTED         no transaction           True     nested

  SUPPORTS       inside @Transactional    True     inTransaction
  SUPPORTS       no transaction           False    supports

  NOT_SUPPORTED  inside @Transactional    False    notSupported
  NOT_SUPPORTED  no transaction           False    notSupported

  MANDATORY      inside @Transactional    True     inTransaction
  MANDATORY      no transaction           --       IllegalTransactionStateException

  NEVER          inside @Transactional    --       IllegalTransactionStateException
  NEVER          no transaction           False    never


Reading it:
  REQUIRED      inside a transaction the inner name is the OUTER method -- it joined.
  REQUIRES_NEW  the inner name is its own method -- it started a second transaction.
  NESTED        fails outright on JpaTransactionManager. See docs/output/03-nested.txt.
  SUPPORTS      joins if there is one, runs with none if there is not. No transaction
                is created, so the write below it lands on an auto-commit connection.
  NOT_SUPPORTED suspends the outer transaction: active=False even inside one.
  MANDATORY     requires a caller's transaction; IllegalTransactionStateException if none.
  NEVER         requires the absence of one; IllegalTransactionStateException if present.

== the exact exception messages ==
  NESTED (withOuterTransaction)
    org.springframework.transaction.NestedTransactionNotSupportedException
    Transaction manager does not allow nested transactions by default - specify 'nestedTransactionAllowed' property with value 'true'

  MANDATORY (withoutOuterTransaction)
    org.springframework.transaction.IllegalTransactionStateException
    No existing transaction found for transaction marked with propagation 'mandatory'

  NEVER (withOuterTransaction)
    org.springframework.transaction.IllegalTransactionStateException
    Existing transaction found for transaction marked with propagation 'never'

== what the transaction manager logged while doing it ==

o.s.orm.jpa.JpaTransactionManager: Creating new transaction with name [com.ankurm.tx.service.SilentlyNonTransactional.properlyCalled]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
o.s.orm.jpa.JpaTransactionManager: Initiating transaction commit
o.s.orm.jpa.JpaTransactionManager: Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.deleteAll]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
o.s.orm.jpa.JpaTransactionManager: Initiating transaction commit
o.s.orm.jpa.JpaTransactionManager: Creating new transaction with name [com.ankurm.tx.service.SilentlyNonTransactional.checkedExceptionCommits]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
o.s.orm.jpa.JpaTransactionManager: Participating in existing transaction
o.s.orm.jpa.JpaTransactionManager: Initiating transaction commit
o.s.orm.jpa.JpaTransactionManager: Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.existsById]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly
o.s.orm.jpa.JpaTransactionManager: Initiating transaction commit
o.s.orm.jpa.JpaTransactionManager: Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.existsById]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly
o.s.orm.jpa.JpaTransactionManager: Initiating transaction commit
o.s.orm.jpa.JpaTransactionManager: Creating new transaction with name [com.ankurm.tx.service.SilentlyNonTransactional.swallowsException]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
o.s.orm.jpa.JpaTransactionManager: Participating in existing transaction
o.s.orm.jpa.JpaTransactionManager: Initiating transaction commit
o.s.orm.jpa.JpaTransactionManager: Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.existsById]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly
o.s.orm.jpa.JpaTransactionManager: Initiating transaction commit
o.s.orm.jpa.JpaTransactionManager: Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.existsById]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly
o.s.orm.jpa.JpaTransactionManager: Initiating transaction commit
o.s.orm.jpa.JpaTransactionManager: Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.deleteAll]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
o.s.orm.jpa.JpaTransactionManager: Initiating transaction commit
o.s.orm.jpa.JpaTransactionManager: Creating new transaction with name [com.ankurm.tx.service.OuterService.inTransaction]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
o.s.orm.jpa.JpaTransactionManager: Participating in existing transaction
o.s.orm.jpa.JpaTransactionManager: Participating in existing transaction
o.s.orm.jpa.JpaTransactionManager: Participating in existing transaction
