What are transactional propagation types in Spring and what are their use cases?
In Spring, transactional propagation types define how a transactional method behaves when called from another transactional method or when initiating a new transaction. They govern the scope of the physical transaction, ensuring data consistency and integrity.
Understanding Transactional Propagation
Transactional propagation in Spring determines how transactional boundaries are managed when multiple transactional methods interact. It dictates whether a method should join an existing transaction, create a new one, or execute non-transactionally. This is crucial for maintaining data consistency across complex business operations.
Key Transactional Propagation Types and Their Use Cases
REQUIRED (Default)
If a transaction already exists, the method joins it. If not, a new transaction is created. This is the most common propagation type and often the appropriate choice for most business operations.
Use Case: Suitable for most service layer operations where business logic should run within a transaction, and nested calls should share the same transaction context to ensure atomicity across multiple operations (e.g., creating a user and their default settings).
SUPPORTS
If a transaction already exists, the method runs within it. If no transaction exists, the method runs non-transactionally.
Use Case: Useful for read-only operations or optional transactional behavior where the method can benefit from an existing transaction but does not strictly require one. For instance, a logging service that might be called from both transactional and non-transactional contexts.
MANDATORY
The method must be executed within an existing transaction. If no transaction is active, an IllegalTransactionStateException is thrown.
Use Case: Ensures that a method is always part of a larger, already-defined transaction. This is useful for critical operations that absolutely depend on an active transaction context to maintain data integrity, typically invoked by another transactional method.
NEVER
The method must not be executed within an existing transaction. If a transaction is active, an IllegalTransactionStateException is thrown. The method always runs non-transactionally.
Use Case: For operations that must explicitly run outside any transaction, such as sending emails, publishing events to an external system, or updating non-transactional caches, especially when these actions should not be rolled back with the main transaction.
NOT_SUPPORTED
The method always runs non-transactionally. If a transaction is active, it is suspended before the method executes and resumed after the method completes.
Use Case: Similar to NEVER, but allows the method to temporarily suspend an existing transaction. This is useful for operations that should not participate in a transaction but are less strict than NEVER, such as logging or certain cache updates that should happen regardless of the calling transaction's outcome.
REQUIRES_NEW
Always creates a new, independent transaction. If a transaction is already active, it is suspended before the new transaction is started, and resumed after the new transaction completes. The new transaction has its own commit/rollback scope, independent of the calling transaction.
Use Case: For operations that need to be committed or rolled back independently of the calling transaction. For example, logging audit trails, sending critical notifications, or persisting retry attempts, where the success/failure of this specific operation should not affect or be affected by the main transaction.
NESTED
If a transaction is active, it creates a nested transaction (a "savepoint" in JDBC). If no transaction is active, it behaves like REQUIRED. A nested transaction can commit or roll back independently of its parent, but its commit is only truly finalized when the parent commits. A rollback of the parent transaction will roll back the nested transaction as well.
Use Case: Allows partial rollbacks within a larger transaction. This is often used for operations that might fail but shouldn't cause the entire parent transaction to fail, allowing the parent to catch the exception and continue. Requires a JDBC 3.0 driver or JTA transaction manager supporting savepoints.
Summary of Propagation Types
| Propagation Type | Behavior with Existing Transaction | Behavior without Existing Transaction | Common Use Case |
|---|---|---|---|
| REQUIRED | Joins existing | Creates new | Most business logic operations (default) |
| SUPPORTS | Joins existing | Executes non-transactionally | Read-only operations, optional transactional |
| MANDATORY | Throws exception | Throws exception | Critical operations requiring existing transaction |
| NEVER | Throws exception | Executes non-transactionally | Operations that must always be non-transactional |
| NOT_SUPPORTED | Suspends existing | Executes non-transactionally | Logging, external calls that shouldn't participate |
| REQUIRES_NEW | Suspends existing, creates new | Creates new | Independent commit/rollback operations (e.g., audit logging) |
| NESTED | Creates nested (savepoint) | Creates new | Partial rollbacks within a larger transaction |