Spring Framework provides two primary approaches for managing transactions:
- Declarative Transaction Management – using annotations or XML configuration
- Programmatic Transaction Management – managing transactions manually in code
Both approaches use Spring’s PlatformTransactionManager under the hood but differ in how and where the transaction logic is applied.
1. What Is Transaction Management in Spring?
Transaction management ensures data consistency in the event of success or failure in a group of operations (e.g., a database insert followed by an update). If something goes wrong, the entire transaction can be rolled back.
2. Declarative Transaction Management
In declarative transaction management, you declare the transactional behavior using annotations or XML, and Spring handles the transaction boundaries automatically.
Using @Transactional annotation:
@Service
public class OrderService {
@Transactional
public void placeOrder(Order order) {
orderRepository.save(order);
paymentService.debitAccount(order.getUser(), order.getAmount());
}
}
Here, Spring will:
- Start a transaction before the method
- Commit if it completes
- Roll back if a runtime exception occurs
How It Works Internally
Spring uses AOP (Aspect-Oriented Programming) to create a proxy around the method or class. The proxy:
- Begins a transaction before the method
- Commits after success
- Rolls back on unhandled exceptions
Pros of Declarative Transaction Management
| Benefit | Description |
|---|---|
| Clean Code | Keeps business logic free from transaction code |
| Less Error-Prone | Spring manages commit/rollback automatically |
| Standard Practice | Well-supported and recommended in most cases |
| Granular Control | Allows per-method control using @Transactional |
3. Programmatic Transaction Management
In programmatic transaction management, you manage transactions manually in code using TransactionTemplate or PlatformTransactionManager.
Example using TransactionTemplate
@Service
public class OrderService {
private final TransactionTemplate transactionTemplate;
@Autowired
public OrderService(PlatformTransactionManager txManager) {
this.transactionTemplate = new TransactionTemplate(txManager);
}
public void placeOrder(Order order) {
transactionTemplate.executeWithoutResult(status -> {
orderRepository.save(order);
paymentService.debitAccount(order.getUser(), order.getAmount());
});
}
}
Alternative using PlatformTransactionManager directly
TransactionStatus status = txManager.getTransaction(new DefaultTransactionDefinition());
try {
orderRepository.save(order);
paymentService.debitAccount(order.getUser(), order.getAmount());
txManager.commit(status);
} catch (Exception e) {
txManager.rollback(status);
throw e;
}
Pros of Programmatic Transaction Management
| Benefit | Description |
|---|---|
| Fine-Grained Control | Full control over transaction boundaries, rollback conditions |
| Dynamic Transaction Behavior | Change behavior at runtime (e.g., skip transaction for dry-run mode) |
| Multiple Transactions | Manually manage nested or independent transactions |
4. When to Use Declarative vs Programmatic?
| Scenario | Recommendation | Reason |
|---|---|---|
| Most business logic | Declarative | Clean, readable, less boilerplate |
| Simple services | Declarative | One method = one transaction, easy to annotate |
| Complex workflows with branching logic | Programmatic | Allows conditional rollback or commit |
| Transactions across multiple methods | Programmatic (or split into one method) | More control over transaction boundary |
| Interacting with multiple data sources | Programmatic | Control order of commits/rollbacks |
| Transactional logic in library code | Programmatic | Library cannot assume annotation behavior |
| Need to retry on specific exceptions | Programmatic or @Transactional + Retry | Custom rollback strategies |
5. Key Differences
| Feature | Declarative (@Transactional) | Programmatic (TransactionTemplate) |
|---|---|---|
| Code Style | Annotations | Java code |
| Complexity | Simple to use | More verbose |
| Control | Limited to what annotations support | Full manual control |
| Best For | Typical business services | Complex transactional workflows |
| Rollback Policy | Runtime exceptions only (by default) | You decide based on any logic |
| Nested Transactions | Controlled via propagation | Full control |
| Testing | Easier with annotations | Might need mocks or manual cleanup |
