== 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