@Transactional Annotation
JavaSpring Boot

How to use @Transactional annotation in a spring boot application

The @Transactional annotation in Spring Boot is a powerful mechanism that provides declarative transaction management for applications. It simplifies the process of managing transactions in a Spring application by allowing developers to annotate methods or classes with @Transactional to specify the transactional behaviour. This annotation is a key component for ensuring data consistency and integrity in database operations.

Understanding Transactions

A transaction is a sequence of one or more operations on a database that should be executed as a single unit of work. In the context of Spring Boot, a transaction typically involves database operations, and the @Transactional annotation helps in managing these transactions.

Core Concepts:

  • ACID Properties: Transactions in databases adhere to the ACID properties – Atomicity, Consistency, Isolation, and Durability.
  • Atomicity: All operations in a transaction must succeed, or none should be applied.
  • Consistency: The database should transition from one consistent state to another after a transaction.
  • Isolation: Transactions should be isolated from each other, and the execution of one transaction should not affect the execution of others.
  • Durability: Once a transaction is committed, its effects are permanent.

Using @Transactional

Basic Usage:

The @Transactional annotation can be applied to methods or classes. When applied at the method level, it indicates that the method should be executed within a transaction. When applied at the class level, all methods within the class become transactional.

@Service
@Transactional
public class MyTransactionalService {

    @Autowired
    private UserRepository userRepository;

    public User saveUser(User user) {
        return userRepository.save(user);
    }

    public List<User> getAllUsers() {
        return userRepository.findAll();
    }
}

In this example, both saveUser and getAllUsers methods are transactional.

Propagation:

@Transactional provides the propagation attribute that controls how the transaction should behave when methods are called within an existing transaction.

@Transactional(propagation = Propagation.REQUIRED)
public void methodInTransaction() {
    // ...
}
  • Propagation.REQUIRED: If a transaction exists, use it. Otherwise, create a new one.
  • Propagation.REQUIRES_NEW: Always create a new transaction, suspending the current one if it exists.
  • Propagation.NESTED: Similar to REQUIRED but starts a nested transaction if one exists.

Isolation:

The isolation attribute specifies the isolation level of the transaction.

@Transactional(isolation = Isolation.READ_COMMITTED)
public void methodWithIsolation() {
    // ...
}

Isolation levels include READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, and SERIALIZABLE.

Rollback:

The @Transactional annotation supports the rollbackFor attribute, allowing you to specify exceptions that should trigger a rollback.

@Transactional(rollbackFor = Exception.class)
public void methodWithRollback() {
    // ...
}

Timeout:

The timeout attribute defines the maximum time (in seconds) that the transaction should take.

@Transactional(timeout = 30)
public void methodWithTimeout() {
    // ...
}

Read-Only:

For methods that only read data without modifying it, you can set readOnly to true for performance optimization.

@Transactional(readOnly = true)
public List<User> getAllUsersReadOnly() {
    return userRepository.findAll();
}

Nested Transactions:

Nested transactions are supported using the @Transactional annotation.

@Transactional
public void outerTransaction() {
    // ...

    innerTransaction();

    // ...
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void innerTransaction() {
    // ...
}

Example Application

Let’s create a simple Spring Boot application to illustrate the usage of @Transactional. For this example, assume we have a UserService interacting with a UserRepository to perform user-related operations.

@Service
@Transactional
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public User saveUser(User user) {
        return userRepository.save(user);
    }

    public List<User> getAllUsers() {
        return userRepository.findAll();
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void updateUser(User user) {
        userRepository.save(user);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    public void deleteUser(Long userId) {
        userRepository.deleteById(userId);
    }
}

In this example:

  • saveUser and getAllUsers are part of the default transaction.
  • updateUser starts a new transaction.
  • deleteUser specifies that if a RuntimeException occurs, the transaction should be rolled back.

Configuring @Transactional

For @Transactional to work, make sure your Spring Boot application is properly configured. Ensure the following:

Enable Transaction Management:In your main application class, use the @EnableTransactionManagement annotation:

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

Configure Data Source and JPA:Make sure your application.properties or application.yml includes configurations for the data source and JPA:

spring.datasource.url=jdbc:mysql://localhost:3306/mydatabase
spring.datasource.username=root
spring.datasource.password=password
spring.jpa.show-sql=true

Adjust the values according to your database setup.

Transaction Manager:Spring Boot automatically configures a PlatformTransactionManager bean. Ensure you have no conflicting configurations. If needed, you can define a custom transaction manager:

@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(entityManagerFactory);
    return transactionManager;
}

The @Transactional annotation in Spring Boot simplifies the management of transactions in a declarative manner. Understanding its attributes, such as propagation, isolation, rollback behavior, and more, allows developers to fine-tune transactional behavior to suit the needs of their applications. When used correctly, @Transactional contributes to maintaining data consistency and integrity in Spring Boot applications.

You can read the documentation here – @Transactional Annotation

In the last post we had discussed How to use @Profile annotation in a spring boot application.

Happy Learning!

Subscribe to the BitsToGigs Newsletter

What's your reaction?

Excited
0
Happy
0
In Love
0
Not Sure
0
Silly
0

You may also like

More in:Java

Leave a reply

Your email address will not be published. Required fields are marked *