← Назад к вопросам

Вызовется ли @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));
    }
}

Что происходит под капотом

  1. processOrder() начинается → Spring создаёт транзакцию A
  2. Встречается вызов logAudit() → Spring видит @Transactional(REQUIRES_NEW)
  3. Текущая транзакция A ПРИОСТАНАВЛИВАЕТСЯ (suspend)
  4. Создаётся НОВАЯ транзакция B для logAudit
  5. logAudit выполняется → commit/rollback транзакции B
  6. Транзакция A возобновляется (resume)
  7. 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()."