DEV Community

Anh Trần Tuấn
Anh Trần Tuấn

Posted on • Originally published at tuanh.net on

Using @Transactional in Spring Boot: A Comprehensive Guide with Code Examples

1. What is @Transactional in Spring Boot?

@Transactional is an annotation in Spring that manages transaction boundaries for methods. It allows developers to define a block of code that needs to be executed within a transactional context. Transactions ensure that a series of operations on the database are atomic, meaning they either all succeed or all fail.

1.1 Why Are Transactions Important?

Transactions play a vital role in maintaining data integrity. In case of a failure in one part of a transaction, @Transactional ensures that all database modifications in that transaction are rolled back, preventing partial updates.

Image

2. How Does @Transactional Work?

The magic behind @Transactional lies in Spring’s AOP (Aspect-Oriented Programming). When a method annotated with @Transactional is called, Spring creates a proxy for that method. This proxy starts a transaction before the method executes, and commits or rolls it back afterward, depending on the outcome.

2.1 Understanding Propagation

The propagation setting defines how the transaction behaves when multiple transactional methods are called. The most common types are:

  • REQUIRED : If there's an existing transaction, join it. If not, create a new one.
  • REQUIRES_NEW : Always create a new transaction, suspending any existing one.
  • MANDATORY : Requires an existing transaction; throws an exception if none exists.

Example:

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void createNewOrder(Order order) {
    orderRepository.save(order);
}
Enter fullscreen mode Exit fullscreen mode

In this example, createNewOrder() will always run in a new transaction, even if it’s called from another transactional method.

2.2 Isolation Levels in Transactions

Transaction isolation defines how data modifications made by one transaction are visible to other concurrent transactions. Spring provides several isolation levels:

  • READ_COMMITTED : The default isolation level where a transaction can only read committed data.
  • REPEATABLE_READ : Ensures that if a transaction reads data, no other transaction can modify it until the first transaction completes.
@Transactional(isolation = Isolation.READ_COMMITTED)
public void updateOrder(Order order) {
    orderRepository.save(order);
}
Enter fullscreen mode Exit fullscreen mode

3. Practical Usage: Demo Code

Let’s create a practical example that demonstrates how @Transactional works in real-world scenarios. Consider a service for handling customer orders.

3.1 Service Class Example

@Service
public class OrderService {

    @Autowired
    private OrderRepository orderRepository;

    @Transactional
    public void processOrder(Order order) {
        // Step 1: Save order
        orderRepository.save(order);

        // Step 2: Simulate an error to trigger rollback
        if(order.getAmount() > 1000) {
            throw new RuntimeException("Order amount too high!");
        }

        // Step 3: More operations can go here
    }
}
Enter fullscreen mode Exit fullscreen mode

In this example, the processOrder() method is transactional. If the order amount exceeds 1000, a RuntimeException is thrown, and the entire transaction is rolled back, meaning no changes are saved to the database.

3.2 Testing Rollback

Let’s simulate this in a simple test:

@SpringBootTest
class OrderServiceTest {

    @Autowired
    private OrderService orderService;

    @Test
    public void testTransactionRollback() {
        Order highAmountOrder = new Order();
        highAmountOrder.setAmount(1500);

        // This should throw an exception and rollback the transaction
        assertThrows(RuntimeException.class, () -> orderService.processOrder(highAmountOrder));

        // Assert that the order was not saved
        assertNull(orderRepository.findById(highAmountOrder.getId()));
    }
}
Enter fullscreen mode Exit fullscreen mode

Here, we create an order with an amount that will trigger the rollback. The test ensures that the order is not saved to the database, confirming the transaction was rolled back.

4. Common Pitfalls and Best Practices

Even though @Transactional is a powerful tool, there are common pitfalls that developers should be aware of.

4.1 Self-invocation Doesn't Work

One common mistake is calling a transactional method from within the same class. This bypasses the Spring proxy mechanism, so the transaction is never started. To fix this, call the method from an external class or inject the same service bean into itself.

4.2 Rollback on Checked Exceptions

By default, transactions are only rolled back on RuntimeException or Error. If you want to rollback on checked exceptions, you need to specify it explicitly:

@Transactional(rollbackFor = Exception.class)
public void updateOrderStatus(Order order) throws Exception {
    // some logic
}
Enter fullscreen mode Exit fullscreen mode

4.3 Transactional on Class vs Method

You can place @Transactional at the class level, applying it to all methods in that class. However, method-level annotations override the class-level configuration.

5. Conclusion

Mastering @Transactional in Spring Boot is crucial for building robust, reliable, and efficient applications. From understanding propagation and isolation levels to avoiding common pitfalls, using this annotation properly can save you from many transactional nightmares.

Have questions or comments? Feel free to leave them below!

Read posts more at : Using @Transactional in Spring Boot: A Comprehensive Guide with Code Examples

Heroku

Built for developers, by developers.

Whether you're building a simple prototype or a business-critical product, Heroku's fully-managed platform gives you the simplest path to delivering apps quickly — using the tools and languages you already love!

Learn More

Top comments (0)

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

👋 Kindness is contagious

Explore a trove of insights in this engaging article, celebrated within our welcoming DEV Community. Developers from every background are invited to join and enhance our shared wisdom.

A genuine "thank you" can truly uplift someone’s day. Feel free to express your gratitude in the comments below!

On DEV, our collective exchange of knowledge lightens the road ahead and strengthens our community bonds. Found something valuable here? A small thank you to the author can make a big difference.

Okay