How to Implement Reliable Transactional Retries in Spring with @Retryable and RetryTemplate
This guide explains how to use Spring Retry's declarative @Retryable annotation together with @Transactional, as well as the programmatic RetryTemplate and TransactionTemplate, to ensure each retry runs in its own transaction and handles transient database failures reliably.
In enterprise applications, retrying database operations is essential for handling transient issues such as deadlocks, connection glitches, or brief service interruptions. Spring provides both declarative annotations (@Retryable combined with @Transactional) and a fully programmatic approach using RetryTemplate and TransactionTemplate to achieve reliable retry mechanisms.
1. Add Spring Retry to the project
Include the required dependencies in pom.xml:
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>2.0.12</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aspectj</artifactId>
</dependency>2. Enable Spring Retry
Annotate a configuration class with @EnableRetry. Setting order = Ordered.LOWEST_PRECEDENCE gives the retry interceptor the lowest priority so that it wraps the transaction interceptor, ensuring each retry runs in a new transaction.
@Configuration
@EnableRetry(order = Ordered.LOWEST_PRECEDENCE)
public class RetryConfig {
}3. Declarative retry with @Retryable
Combine @Retryable and @Transactional on a service method. Each retry is executed in its own transaction, preventing early‑failed attempts from marking the transaction for rollback.
@Retryable(
maxAttempts = 3,
backoff = @Backoff(delay = 2000)
)
@Transactional
public void processPayment(double amount) {
logger.log(Level.INFO, "Attempt #: {0}", attempt);
Payment payment = new Payment("PENDING", amount);
paymentRepository.save(payment);
// Simulate transient failure on the first two attempts
if (attempt < 3) {
attempt++;
throw new RuntimeException("Simulated transient failure");
}
payment.setStatus("SUCCESS");
paymentRepository.save(payment);
logger.log(Level.INFO, "Payment processed successfully on attempt #: {0}", attempt);
}4. Programmatic retry with RetryTemplate and TransactionTemplate
For scenarios requiring fine‑grained control over retry policies, exception classification, and transaction boundaries, use the programmatic APIs. The example below creates a RetryTemplate with three attempts and a fixed 100 ms back‑off, then executes the business logic inside a TransactionTemplate.
@Service
public class PaymentServiceProgrammatic {
private static final Logger logger = Logger.getLogger(PaymentServiceProgrammatic.class.getName());
private final PaymentRepository paymentRepository;
private final TransactionTemplate transactionTemplate;
public PaymentServiceProgrammatic(PaymentRepository paymentRepository,
TransactionTemplate transactionTemplate) {
this.paymentRepository = paymentRepository;
this.transactionTemplate = transactionTemplate;
}
private final RetryTemplate retryTemplate = new RetryTemplateBuilder()
.maxAttempts(3)
.fixedBackoff(Duration.ofMillis(100))
.build();
public void processPayment(double amount) {
retryTemplate.execute(context -> {
logger.info("Retry attempt: " + context.getRetryCount());
return transactionTemplate.execute(status -> {
Payment payment = new Payment("PENDING", amount);
paymentRepository.save(payment);
if (context.getRetryCount() < 3) {
throw new RuntimeException("Simulated transient failure");
}
payment.setStatus("SUCCESS");
paymentRepository.save(payment);
logger.info("Payment processed successfully on retry attempt: " + context.getRetryCount());
return null;
});
});
}
}5. Conclusion
Both declarative and programmatic approaches allow Spring applications to perform reliable, transactional retries. By ensuring each retry runs in a fresh transaction, the strategies avoid rollback side effects from earlier failures and guarantee consistent outcomes.
Cognitive Technology Team
Cognitive Technology Team regularly delivers the latest IT news, original content, programming tutorials and experience sharing, with daily perks awaiting you.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
