Spring Boot Tutorial

Spring Boot - Software Setup and Configuration (STS/Eclipse/IntelliJ)

Prerequisite (Spring Core Concepts)

Spring Boot Core

Spring Boot with REST API

Spring Boot with Database and Data JPA

Spring Boot with Kafka

Spring Boot with AOP

Spring Boot - Transaction Management Using @Transactional Annotation

Spring's declarative transaction management is made possible with Spring AOP, and in a Spring Boot application, it's extremely straightforward to use.

The @Transactional annotation is central to Spring's declarative transaction management. When applied, Spring ensures that the method runs within a transaction context. If any RuntimeException is thrown during the method execution, the transaction will be rolled back; otherwise, it will commit.

Here's how you can set up transaction management in a Spring Boot application:

1. Add Dependency

Ensure you have the Spring Data JPA (or the relevant Spring Data project for your datastore) starter dependency in your pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

2. Enable Transaction Management

While Spring Boot automatically enables transaction management if Spring Data is on the classpath, it's still considered a good practice to explicitly enable it using @EnableTransactionManagement in your main configuration class:

@SpringBootApplication
@EnableTransactionManagement
public class YourApplication {
    public static void main(String[] args) {
        SpringApplication.run(YourApplication.class, args);
    }
}

3. Use @Transactional Annotation

You can now use the @Transactional annotation on methods that you want to be transactional:

@Service
public class SomeService {

    @Autowired
    private SomeRepository someRepository;

    @Transactional
    public void someTransactionalMethod(SomeEntity entity) {
        // multiple database operations
        someRepository.save(entity);
        // ... other operations
        // If any operation fails, all operations in this method will be rolled back.
    }
}

Some Points to Note:

  • Propagation: By default, if a transactional method is executed within the context of an existing transaction, it will run within that transaction (this is called REQUIRED propagation). But you can customize this using the propagation attribute of @Transactional.

  • Isolation: You can specify how your transaction interacts with other concurrent transactions using the isolation attribute of @Transactional.

  • Rollback: By default, Spring rolls back the transaction if a checked exception or unchecked exception (i.e., runtime exception) is thrown. If you want to customize which exceptions trigger a rollback, you can use the rollbackFor and noRollbackFor attributes of @Transactional.

  • Read-Only: If a method only reads data without modifying it, you can set the readOnly attribute to true. This can be a performance optimization hint for some datastores.

  • Timeout: You can specify a timeout for the annotated method, after which if the transaction is not complete, it will be rolled back.

Remember, transaction management is an essential aspect of any application that interacts with a database. It ensures data consistency and integrity, especially when multiple operations are executed as a single unit of work.

  1. Configuring and using @Transactional in Spring Boot:

    • Description: Use the @Transactional annotation to demarcate transaction boundaries on methods or classes. This annotation is placed on methods that should run within a transaction.
    • Code:
      @Service
      public class MyService {
          @Transactional
          public void performTransaction() {
              // Transactional logic
          }
      }
      
  2. Transactional boundaries and isolation levels in Spring Boot:

    • Description: Define transactional boundaries to encapsulate a series of operations. Specify isolation levels to control the degree of isolation between transactions.
    • Code:
      @Transactional(isolation = Isolation.READ_COMMITTED)
      public void performTransactionalOperation() {
          // Transactional logic
      }
      
  3. Nested transactions with @Transactional in Spring Boot:

    • Description: Use the @Transactional annotation on nested methods to create nested transactions. The behavior depends on the underlying transaction manager.
    • Code:
      @Transactional
      public void outerTransaction() {
          // Transactional logic
          innerTransaction();
      }
      
      @Transactional(propagation = Propagation.REQUIRES_NEW)
      public void innerTransaction() {
          // Nested transactional logic
      }
      
  4. Propagation behavior in @Transactional of Spring Boot:

    • Description: Control how transactions propagate to nested methods using the propagation attribute. Options include REQUIRED, REQUIRES_NEW, SUPPORTS, and more.
    • Code:
      @Transactional(propagation = Propagation.REQUIRED)
      public void requiredPropagation() {
          // Transactional logic
      }
      
  5. Rollback conditions and exceptions in Spring Boot transactions:

    • Description: Specify conditions for automatic rollback using the rollbackFor and noRollbackFor attributes. Define exceptions that trigger rollback or non-rollback.
    • Code:
      @Transactional(rollbackFor = { CustomException.class })
      public void performTransactionalOperation() throws CustomException {
          // Transactional logic
      }
      
  6. Transactional read and write operations in Spring Boot:

    • Description: Distinguish between read-only and read-write transactions. Use the readOnly attribute to optimize read-only transactions.
    • Code:
      @Transactional(readOnly = true)
      public String fetchReadOnlyData() {
          // Read-only transactional logic
      }
      
  7. Testing and debugging transactions in Spring Boot:

    • Description: Test transactions using the @Transactional annotation in test methods. Debug transactions to understand their behavior during runtime.
    • Code:
      @Transactional
      public void testTransactionalOperation() {
          // Test logic with transactions
      }