Spring Transactions Propagation Levels

What are Spring Transactions Propagation Levels?

Spring Transactions Propagation Levels define how transactions should be handled when multiple transactional methods are invoked within a single transactional context. These levels allow you to control the behavior of transactional methods, such as whether they should join an existing transaction or create a new one.

Let's explore the different Spring Transactions Propagation Levels:

1. PROPAGATION_REQUIRED

PROPAGATION_REQUIRED is the default propagation level. When a method annotated with this level is invoked, it will join an existing transaction if available. If no transaction exists, a new one will be created. This level ensures that all transactional methods participate in a single transactional context.

Example:

@Transactional(propagation = Propagation.REQUIRED)
public void updateCustomerInfo(Customer customer) {
// Perform database updates
}
@Transactional(propagation = Propagation.REQUIRED)
public void processOrder(Order order) {
// Perform order processing
updateCustomerInfo(order.getCustomer());
}

In the example above, both the `updateCustomerInfo` and `processOrder` methods are transactional with PROPAGATION_REQUIRED. If `processOrder` is called within an existing transaction, it will join that transaction. Otherwise, a new transaction will be created, ensuring that both methods operate within the same transactional context.

2. PROPAGATION_REQUIRES_NEW

PROPAGATION_REQUIRES_NEW always creates a new transaction. If a transaction already exists, it will be suspended until the new transaction completes. This level ensures that each method operates in its independent transactional context.

Example:

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void processOrder(Order order) {
// Perform order processing
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateInventory(Order order) {
// Update inventory
processOrder(order);
}

In the example above, the `updateInventory` method is transactional with PROPAGATION_REQUIRES_NEW. Even if it is called within an existing transaction, a new transaction will be created, allowing `updateInventory` and `processOrder` to operate independently in their respective transactional contexts.

3. PROPAGATION_SUPPORTS

PROPAGATION_SUPPORTS allows a method to participate in a transactional context if one exists. If no transaction is present, the method executes non-transactionally. It effectively says, "If there's a transaction, I'll participate; otherwise, I'll run as non-transactional."

Example:

@Transactional(propagation = Propagation.SUPPORTS)
public void retrieveCustomerInfo(int customerId) {
// Retrieve customer information
}

In the example above, the `retrieveCustomerInfo` method is transactional with PROPAGATION_SUPPORTS. If it is called within an existing transaction, it participates in that transaction. Otherwise, it executes non-transactionally, allowing the caller to decide whether to start a transaction or not.

4. PROPAGATION_NOT_SUPPORTED

PROPAGATION_NOT_SUPPORTED specifies that a method should execute non-transactionally, regardless of the presence of an active transaction. If a transaction is already active, it will be suspended for the duration of the method execution.

When you have methods that only read data from the database but don't modify it, you can use NOT_SUPPORTED. It allows these methods to run without a transaction, potentially improving performance.

Example:

@Transactional(propagation = Propagation.REQUIRED)    public void create(Product product, List<Image> images) {
saveImages(images);
productRepository.save(product);
}

@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void saveImages(List<Image> images) {
createImages(images);
}

In the example above, the `saveImages` method is transactional with PROPAGATION_NOT_SUPPORTED. It executes non-transactionally, even if it is called within an existing transaction. This level is useful when you explicitly want to exclude a method from any transactional context.

5. PROPAGATION_MANDATORY

PROPAGATION_MANDATORY specifies that a method must execute within an active transaction. If no transaction is present, a `TransactionRequiredException` is thrown.

Always behaves like REQUIRED. When you want to ensure that a specific method is always executed within the context of a transaction, it can be crucial for maintaining data consistency and integrity. You can use of this such this scenario, for instance, payment. You want to ensure a payment method must be included in a transaction.

Example:

@Transactional(propagation = Propagation.MANDATORY)
public void updateAccountBalance(double amount) {
// Update account balance within an active transaction
}

In the example above, the `updateAccountBalance` method is transactional with PROPAGATION_MANDATORY. It requires an existing transaction for execution. If called without an active transaction, an exception will be thrown.

Conclusion

Understanding Spring Transactions Propagation Levels is crucial for managing database transactions effectively. By choosing the appropriate propagation level, you can control how transactions are propagated and ensure data integrity within your applications. In this blog post, we explored five common propagation levels: REQUIRED, REQUIRES_NEW, SUPPORTS, NOT_SUPPORTED, and MANDATORY, along with practical examples to illustrate their usage.

Post a Comment

Previous Post Next Post