Ответ
Аннотация @Transactional в Spring декларативно управляет транзакциями, избавляя от необходимости писать шаблонный код для их начала, коммита или отката.
Ключевые параметры:
| Параметр | Описание | Пример значения |
|---|---|---|
propagation |
Поведение транзакции относительно существующей. | Propagation.REQUIRED (по умолчанию) — использует текущую или создаёт новую. REQUIRES_NEW — всегда создаёт новую. |
isolation |
Уровень изоляции транзакции. | Isolation.READ_COMMITTED (чаще всего) — читаются только закоммиченные данные. |
timeout |
Таймаут транзакции в секундах. | 30 |
readOnly |
Оптимизация для операций только чтения. | true |
rollbackFor / noRollbackFor |
Классы исключений для отката/игнорирования отката. | rollbackFor = Exception.class |
Пример использования:
@Service
public class TransferService {
@Autowired
private AccountRepository accountRepository;
@Transactional(
propagation = Propagation.REQUIRED,
isolation = Isolation.READ_COMMITTED,
timeout = 30,
rollbackFor = {InsufficientFundsException.class, DataAccessException.class}
)
public void transferMoney(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);
// При любом исключении из указанных в rollbackFor произойдёт откат обоих save
}
}
Важные ограничения:
- Работает только на public-методах.
- Самовызов внутри класса (вызов одного
@Transactional-метода из другого метода того же класса) не работает из-за ограничений AOP-проксирования. Для этого нужно использоватьself-injectionилиAspectJmode. - По умолчанию откат происходит только для
RuntimeExceptionиError.