Transaction Propagation in Multi-Service Calls
Desliza para mostrar el menú
Transaction Propagation in Multi-Service Calls
When working with business logic that spans multiple services, you often need to ensure that all operations either succeed or fail together. Spring provides robust transaction propagation mechanisms to manage this requirement, even when service methods call each other during runtime.
Transaction propagation determines how a transactional context behaves when a method annotated with @Transactional calls another transactional method. Spring evaluates the current transaction state and applies the specified propagation behavior, such as joining an existing transaction or creating a new one.
At runtime, Spring uses proxies to intercept method calls. When you invoke a transactional service method, the proxy checks if a transaction is already active. If so, it decides—based on the propagation setting—whether to reuse the current transaction, suspend it, or start a new one. This decision is made dynamically for every method call, ensuring that each operation participates in the right transactional context.
How Propagation Modes Are Resolved at Runtime
Spring resolves transaction propagation at runtime by checking the current transaction context and the propagation setting of the method being called. Here is what happens behind the scenes:
- When you call a method with
@Transactional, Spring examines the propagation type specified; - If there is already an active transaction, Spring decides whether to join, suspend, or start a new one based on the propagation mode;
- If there is no active transaction, Spring creates a new transaction only if the propagation mode requires it.
Common Propagation Modes and Their Behavior
- REQUIRED: Joins the current transaction if one exists; otherwise, creates a new transaction. Most common default;
- REQUIRES_NEW: Always suspends the existing transaction (if any), then creates a new, independent transaction. After method completion, the original transaction resumes;
- NESTED: If a transaction exists, creates a nested transaction (using a savepoint); otherwise, starts a new transaction. Nested transactions allow partial rollbacks inside a larger transaction;
- SUPPORTS: Joins the current transaction if one exists; if not, runs non-transactionally;
- NOT_SUPPORTED: Suspends any existing transaction and runs non-transactionally;
- MANDATORY: Joins the current transaction; throws an exception if no transaction exists;
- NEVER: Runs non-transactionally; throws an exception if a transaction exists.
How Suspension and Joining Work
Spring manages transaction contexts using a stack model. When a method with REQUIRES_NEW or NOT_SUPPORTED is called and there is an active transaction, Spring suspends the current transaction context and starts a new one or runs without one. When the method finishes, Spring resumes the previous transaction context. If a method uses REQUIRED or SUPPORTS, it will join the existing transaction context.
Example: REQUIRES_NEW in Multi-Service Calls
Suppose ServiceA calls ServiceB, and both methods are annotated with @Transactional, but ServiceB uses REQUIRES_NEW:
ServiceA.method()starts and creates a transaction (if not already present);ServiceAcallsServiceB.method(), which suspends the current transaction and starts a new one;ServiceB.method()completes, commits or rolls back its transaction, and the original transaction fromServiceAresumes.
This approach allows you to control how transactions behave across multiple service calls, ensuring data consistency and isolation as required by your application's business logic.
Nested Service Calls and Transaction Propagation
When you call one service method from another within the same transaction, Spring manages the transaction context according to the configured propagation behavior. Understanding what happens when a nested service call fails is key to building reliable applications.
What Happens During Nested Service Calls?
- The outer service method starts and may create a transaction, depending on its propagation setting;
- The inner service method is called. Its transaction behavior depends on its own propagation setting and whether a transaction is already active;
- If the inner method throws a runtime exception (or a checked exception configured for rollback), Spring marks the current transaction as rollback-only;
- After the inner method fails, control returns to the outer method. If the outer method does not handle the exception, the transaction is rolled back when the method exits;
- If the exception is caught and suppressed in the outer method, the transaction is still marked as rollback-only. Any attempt to commit will result in a rollback.
Rollback Behavior
- Default propagation (
REQUIRED): Both methods share the same transaction. If either method fails, the entire transaction rolls back; - New transaction (
REQUIRES_NEW): The inner method runs in a separate transaction. If the inner method fails, only its transaction rolls back. The outer transaction can still commit, unless an exception is thrown up to the outer method; - No transaction (
NOT_SUPPORTED): The inner method runs outside of any transaction. Its failure does not affect the outer transaction.
Transaction Context Handling
- Spring maintains a transaction context for each thread. When a nested method joins an existing transaction, it shares the same context;
- If a new transaction is created (
REQUIRES_NEW), Spring suspends the current context and creates a new one. After the inner method completes, Spring resumes the original context; - If a transaction is marked as rollback-only, Spring prevents any commit and ensures data integrity by rolling back all changes made within that transaction context.
¡Gracias por tus comentarios!
Pregunte a AI
Pregunte a AI
Pregunte lo que quiera o pruebe una de las preguntas sugeridas para comenzar nuestra charla