← Назад к вопросам
Вызовется ли @Transactional (Propagation: REQUIRES_NEW) метод b из @Transactional метода a?
2.7 Senior🔥 91 комментариев
#Spring Boot и Spring Data#Spring Framework#Базы данных и SQL
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# @Transactional с PROPAGATION.REQUIRES_NEW: вызовется ли метод b из метода a?
Краткий ответ
ДА, метод b будет вызван и выполнен в ОТДЕЛЬНОЙ транзакции, даже если он вызывается из метода a с активной транзакцией. Это основное назначение REQUIRES_NEW.
Как это работает
Теория
@Service
public class OrderService {
@Transactional // Транзакция A
public void processOrder(Order order) {
// Логика обработки заказа
saveOrder(order);
// Вызов метода с REQUIRES_NEW
logAudit(order); // Транзакция B (новая!)
// После возврата из logAudit транзакция B уже закончилась
// Здесь мы снова в транзакции A
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logAudit(Order order) {
// Это выполняется в НОВОЙ, ОТДЕЛЬНОЙ транзакции
// Даже если processOrder имеет открытую транзакцию
auditRepository.save(new AuditLog(order));
}
}
Что происходит под капотом
- processOrder() начинается → Spring создаёт транзакцию A
- Встречается вызов logAudit() → Spring видит @Transactional(REQUIRES_NEW)
- Текущая транзакция A ПРИОСТАНАВЛИВАЕТСЯ (suspend)
- Создаётся НОВАЯ транзакция B для logAudit
- logAudit выполняется → commit/rollback транзакции B
- Транзакция A возобновляется (resume)
- processOrder завершается → commit/rollback транзакции A
Критическое различие: ТРЕБУЕТСЯ прокси
✅ Работает (через Spring прокси)
@Service
public class OrderService {
@Transactional
public void processOrder(Order order) {
// Инъектируем сервис (прокси)
auditService.logAudit(order); // REQUIRES_NEW сработает
}
}
@Service
public class AuditService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logAudit(Order order) { ... }
}
❌ НЕ работает (прямой вызов)
@Service
public class OrderService {
@Transactional
public void processOrder(Order order) {
// НЕПРАВИЛЬНО: вызов this.logAudit() игнорирует @Transactional
this.logAudit(order); // REQUIRES_NEW НЕ сработает!
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logAudit(Order order) { ... }
}
Практический пример: когда REQUIRES_NEW полезен
Задача: логирование ошибок независимо от основной транзакции
@Service
public class OrderService {
@Autowired private AuditService auditService;
@Transactional
public void processPayment(Order order) {
try {
payment.charge(order.getAmount());
order.setStatus("PAID");
orderRepository.save(order);
} catch (PaymentException e) {
// Логируем ошибку в ОТДЕЛЬНОЙ транзакции
// Даже если processPayment откатится, лог останется
auditService.logError(order, e);
throw e;
}
}
}
@Service
public class AuditService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logError(Order order, Exception e) {
// Выполняется в независимой транзакции
// Коммитится сразу, даже если основная откатится
errorLogRepository.save(new ErrorLog(order, e.getMessage()));
}
}
Результат
- Если processPayment выбросит исключение → откатится основная транзакция
- Но logError уже закоммитился в отдельной транзакции
- В БД остаётся лог ошибки, хотя заказ не был обновлён
Другие значения propagation для сравнения
| Propagation | Поведение | Пример использования |
|---|---|---|
| REQUIRED (по умолчанию) | Использует текущую или создаёт новую | Обычные бизнес-операции |
| REQUIRES_NEW | Всегда новая | Аудит, логирование, уведомления |
| SUPPORTS | Использует если есть, иначе без транзакции | Readonly операции |
| NOT_SUPPORTED | Выполняет БЕЗ транзакции | Неэффективные операции |
| NEVER | Запрещает транзакции | Проверка безопасности |
| MANDATORY | Требует существующей | Вспомогательные методы |
| NESTED | Точка сохранения (savepoint) | Откат части операции |
Ответ на собеседовании
Правильный ответ: "Да, метод b будет вызван и выполнен. С REQUIRES_NEW текущая транзакция приостанавливается, создаётся новая независимая транзакция для метода b, она коммитится/откатывается отдельно, а затем исходная транзакция возобновляется. Это полезно для аудита или логирования, которые должны сохраниться даже если основная операция откатится. Важно помнить: это работает только если методы находятся в разных бинах (через прокси), не при прямом вызове this.b()."