@Transactional marks a method, class, or interface as running within a database transaction boundary, so that all the database operations performed inside it are treated as a single atomic unit -- either everything commits together, or, if an exception occurs, everything rolls back together.
Key Points: • Spring implements @Transactional using AOP proxies, so it only takes effect on calls that go through the Spring-managed bean (self-invocation within the same class bypasses it). • By default, @Transactional rolls back on unchecked exceptions (RuntimeException and Error) but not on checked exceptions, unless rollbackFor is specified. • Propagation settings (like REQUIRED, REQUIRES_NEW) control how a transactional method behaves when called from within another transaction. • Isolation level settings control how concurrent transactions see each other's uncommitted changes. • readOnly = true is a useful hint for read-only methods, allowing some persistence providers and databases to optimize accordingly.
Example: A service method that debits one account and credits another is annotated with @Transactional so that if the credit step throws an exception after the debit already ran, Spring rolls back the debit too, leaving the accounts in a consistent state.
Code Example:
@Service
public class TransferService {
@Transactional
public void transfer(Long fromId, Long toId, BigDecimal amount) {
Account from = accountRepository.findById(fromId).orElseThrow();
Account to = accountRepository.findById(toId).orElseThrow();
from.debit(amount);
to.credit(amount);
accountRepository.save(from);
accountRepository.save(to);
}
}Interview Tip: A concise interview answer is:
"@Transactional wraps a method's database operations in a single atomic transaction using a Spring AOP proxy -- if an unchecked exception is thrown, everything rolls back; otherwise it all commits together. A classic use case is a funds transfer, where debiting one account and crediting another must succeed or fail as one unit."