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
andgetAllUsers
are part of the default transaction.updateUser
starts a new transaction.deleteUser
specifies that if aRuntimeException
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