← Назад к вопросам
Как изменять поведение аннотации Transactional в Spring
1.0 Junior🔥 121 комментариев
#Spring Framework
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Ответ
Как изменять поведение аннотации @Transactional в Spring
@Transactional — один из самых мощных механизмов Spring для управления транзакциями. Рассмотрю все параметры и способы кастомизации.
1. Основные параметры @Transactional
@Transactional(
value = "transactionManager", // Какой TransactionManager использовать
propagation = Propagation.REQUIRED, // Как распространяется транзакция
isolation = Isolation.READ_COMMITTED, // Уровень изоляции
timeout = 30, // Таймаут в секундах
readOnly = false, // Только чтение
rollbackFor = Exception.class, // На какие исключения откатывать
noRollbackFor = IgnorableException.class // Какие исключения не откатывать
)
public void complexOperation() {
// код
}
2. Propagation — как распространяется транзакция
@Service
public class OrderService {
// REQUIRED (по умолчанию) — используй существующую, или создай новую
@Transactional(propagation = Propagation.REQUIRED)
public void saveOrder(Order order) {
orderRepository.save(order);
// Если уже в транзакции — используем её, иначе создаём новую
}
// REQUIRES_NEW — всегда создай новую, текущую приостанови
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void auditLog(String action) {
auditRepository.log(action);
// Даже если основная транзакция откатится, аудит сохранится
}
// NESTED — вложенная точка сохранения
@Transactional(propagation = Propagation.NESTED)
public void processPayment(Payment payment) {
paymentService.charge(payment);
}
// MANDATORY — должна быть существующая транзакция
@Transactional(propagation = Propagation.MANDATORY)
public void criticalOperation() {
// Выбросит IllegalTransactionStateException если нет транзакции
}
}
3. Isolation — уровни изоляции
@Service
public class AccountService {
// READ_COMMITTED — стандарт, грязные чтения запрещены
@Transactional(isolation = Isolation.READ_COMMITTED)
public void updateBalance(Long accountId, BigDecimal amount) {
// Безопасно от грязных чтений
}
// REPEATABLE_READ — нет неповторяемых чтений
@Transactional(isolation = Isolation.REPEATABLE_READ)
public void processPayment(Long accountId) {
BigDecimal balance1 = getBalance(accountId);
BigDecimal balance2 = getBalance(accountId);
// balance1 == balance2 гарантировано
}
// SERIALIZABLE — максимальная изоляция
@Transactional(isolation = Isolation.SERIALIZABLE)
public void criticalAudit() {
// Полная изоляция, очень медленно
}
}
4. ReadOnly — оптимизация для чтения
@Service
public class ReportService {
// Для чтения — помечай readOnly = true
@Transactional(readOnly = true)
public List<OrderReport> getMonthlyReport(YearMonth month) {
return orderRepository.findByMonth(month);
// Оптимизировано для чтения
}
// Для записи — по умолчанию readOnly = false
@Transactional
public void saveOrder(Order order) {
orderRepository.save(order);
}
}
5. Timeout — таймаут транзакции
@Service
public class DataProcessingService {
// Таймаут 30 секунд
@Transactional(timeout = 30)
public void processLargeDataset(Long datasetId) {
// Если дольше 30 сек — откатится
}
}
6. RollbackFor / NoRollbackFor
@Service
public class PaymentService {
// Откатывай также на checked исключения
@Transactional(rollbackFor = IOException.class)
public void processWithFile(File file) throws IOException {
// Откатится и на IOException
}
// НЕ откатывай на определённые исключения
@Transactional(noRollbackFor = IgnorableException.class)
public void resilientOperation() {
try {
riskyOperation();
} catch (IgnorableException e) {
logger.warn("Игнорируемая ошибка", e);
// Транзакция НЕ откатится
}
}
}
7. Выбор TransactionManager
@Configuration
public class TransactionConfig {
@Bean("primaryTxManager")
public PlatformTransactionManager primaryTransactionManager(DataSource ds) {
return new DataSourceTransactionManager(ds);
}
@Bean("secondaryTxManager")
public PlatformTransactionManager secondaryTransactionManager(
DataSource secondaryDs) {
return new DataSourceTransactionManager(secondaryDs);
}
}
@Service
public class MultiDatabaseService {
// Используй первый transaction manager
@Transactional("primaryTxManager")
public void saveInPrimary(Entity entity) {
primaryRepository.save(entity);
}
// Используй второй transaction manager
@Transactional("secondaryTxManager")
public void saveInSecondary(Entity entity) {
secondaryRepository.save(entity);
}
}
8. Таблица Propagation режимов
| Режим | Поведение |
|---|---|
| REQUIRED | Используй существующую или создай новую |
| REQUIRES_NEW | Всегда новая (текущую приостановит) |
| NESTED | Вложенная транзакция (savepoint) |
| MANDATORY | Обязательна существующая |
| SUPPORTS | Используй если есть, если нет — без транзакции |
| NOT_SUPPORTED | Выполни без транзакции |
| NEVER | Не должна быть транзакция |
9. Практический пример
@Service
public class ComplexOrderService {
@Transactional(
propagation = Propagation.REQUIRED,
isolation = Isolation.READ_COMMITTED,
timeout = 60,
readOnly = false
)
public Long createOrderWithItems(OrderDTO dto) {
Order order = new Order(dto);
orderRepository.save(order);
for (ItemDTO itemDto : dto.getItems()) {
Item item = new Item(itemDto);
item.setOrder(order);
itemRepository.save(item);
}
return order.getId();
}
@Transactional(readOnly = true)
public OrderDTO getOrder(Long orderId) {
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new NotFoundException("Order not found"));
return new OrderDTO(order);
}
@Transactional(
propagation = Propagation.REQUIRES_NEW,
rollbackFor = Exception.class
)
public void logTransaction(String action, Long orderId) {
auditRepository.save(new AuditLog(action, orderId));
}
}
Best Practices
- Помечай readOnly = true для запросов только на чтение — оптимизирует производительность
- Понимай propagation для вложенных операций — часто нужны REQUIRES_NEW для аудита
- Выбирай правильный isolation уровень — баланс между безопасностью и производительностью
- Указывай timeout для потенциально долгих операций
- Откатывай на checked исключения явно если нужно
- Тестируй откат — убедись, что откатываешь правильно
@Transactional — мощный инструмент для управления транзакциями. Правильная конфигурация критична для надёжности приложения.