Ответ
Аннотация @Transactional в Spring декларативно управляет границами транзакций для методов или классов. При вызове аннотированного метода Spring создает или присоединяется к существующей транзакции, а по завершении — фиксирует (commit) или откатывает (rollback) изменения.
Основной принцип:
- Перед методом: Открывается транзакция (или используется существующая).
- Во время метода: Все операции с БД выполняются в этой транзакции.
- После метода: Если метод завершился успешно (без исключения) — транзакция фиксируется. Если было выброшено исключение — транзакция откатывается.
Ключевые параметры аннотации:
propagation— определяет поведение при вложенных вызовах. Например:REQUIRED(по умолчанию): использует текущую транзакцию или создает новую.REQUIRES_NEW: всегда создает новую транзакцию, приостанавливая текущую.
isolation— уровень изоляции транзакции (например,READ_COMMITTED).rollbackFor/noRollbackFor— указывает, для каких исключений делать или не делать откат.readOnly—trueдля оптимизации операций только на чтение.timeout— таймаут транзакции в секундах.
Пример использования:
@Service
public class TransferService {
@Autowired
private AccountRepository accountRepository;
@Transactional(rollbackFor = {InsufficientFundsException.class})
public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
Account from = accountRepository.findById(fromId).orElseThrow();
Account to = accountRepository.findById(toId).orElseThrow();
if (from.getBalance().compareTo(amount) < 0) {
throw new InsufficientFundsException("Недостаточно средств");
}
from.debit(amount); // Списываем
to.credit(amount); // Зачисляем
// Оба вызова save() выполняются в одной транзакции.
// При исключении балансы не изменятся.
accountRepository.save(from);
accountRepository.save(to);
}
}
Важные ограничения:
- Работает только на public-методах из-за механизма проксирования AOP.
- По умолчанию откатывает транзакцию только для unchecked (
RuntimeException) иErrorисключений. Для checked-исключений отката не будет. - Самовызов метода внутри одного класса (без прокси) не запустит транзакционное поведение.