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

Что такое REQUIRED в propagation?

1.8 Middle🔥 161 комментариев
#Spring Framework

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое REQUIRED в propagation

Propagation.REQUIRED — это значение по умолчанию для управления транзакциями в Spring Framework (аннотация @Transactional). Оно определяет поведение методов внутри цепочки вызовов: если уже существует активная транзакция, использовать её; если нет, создать новую. Это самый частый выбор для большинства приложений.

Что такое Propagation

Propagation (распространение) — это механизм управления транзакциями в Spring, который определяет:

  • Использовать ли существующую транзакцию
  • Создавать ли новую
  • Что делать, если транзакция уже активна

REQUIRED: поведение

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class OrderService {
    
    @Autowired
    private PaymentService paymentService;
    
    @Autowired
    private OrderRepository orderRepository;
    
    // Propagation.REQUIRED — значение по умолчанию
    @Transactional(propagation = Propagation.REQUIRED)
    public Order createOrder(OrderRequest request) {
        // Если нет транзакции — создаём новую
        // Если уже есть — используем её
        
        Order order = new Order(request);
        order = orderRepository.save(order);  // Внутри транзакции
        
        // Вызываем paymentService
        // Его @Transactional(REQUIRED) будет использовать
        // ТУ ЖЕ транзакцию, что и createOrder
        paymentService.processPayment(order);  
        
        return order;
    }
}

@Service
public class PaymentService {
    
    @Autowired
    private PaymentRepository paymentRepository;
    
    @Transactional(propagation = Propagation.REQUIRED)
    public void processPayment(Order order) {
        // Используем СУЩЕСТВУЮЩУЮ транзакцию из createOrder
        // (не создаём новую)
        
        Payment payment = new Payment(order);
        paymentRepository.save(payment);
    }
}

Жизненный цикл транзакции с REQUIRED

Сценарий 1: Нет активной транзакции

orderService.createOrder()
  ├─ BEGIN TRANSACTION  ← Создаём новую
  ├─ INSERT order
  └─ paymentService.processPayment()
       ├─ (использует существующую транзакцию)
       ├─ INSERT payment
       └─ (транзакция продолжает работать)
COMMIT или ROLLBACK


Сценарий 2: Уже есть активная транзакция

@Transactional
public void doSomething() {
  orderService.createOrder()
    ├─ (REQUIRED: используем существующую транзакцию)
    ├─ INSERT order
    └─ paymentService.processPayment()
         ├─ (REQUIRED: используем ту же транзакцию)
         ├─ INSERT payment
         └─ (всё в одной транзакции)
COMMIT или ROLLBACK (для всего блока)
}

Практический пример: REQUIRED vs другие значения

@Service
public class TransactionPropagationDemo {
    
    @Autowired
    private UserRepository userRepository;
    
    // 1. REQUIRED (по умолчанию) — использовать или создать
    @Transactional(propagation = Propagation.REQUIRED)
    public void required() {
        userRepository.save(new User("Alice"));
        // Если вызова из @Transactional метода — используем его транзакцию
        // Если вызова самостоятельно — создаём новую
    }
    
    // 2. REQUIRES_NEW — всегда создать новую
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void requiresNew() {
        userRepository.save(new User("Bob"));
        // ВСЕГДА создаём новую транзакцию, даже если уже есть
    }
    
    // 3. SUPPORTS — поддержать существующую, но не обязательна
    @Transactional(propagation = Propagation.SUPPORTS)
    public void supports() {
        userRepository.save(new User("Charlie"));
        // Если есть транзакция — используем
        // Если нет — работаем без транзакции (Auto-commit)
    }
    
    // 4. NOT_SUPPORTED — НЕ использовать транзакцию
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void notSupported() {
        // Если есть транзакция — приостанавливаем её
        userRepository.save(new User("Diana"));
        // После выполнения — возобновляем внешнюю транзакцию
    }
    
    // 5. MANDATORY — транзакция ОБЯЗАТЕЛЬНА
    @Transactional(propagation = Propagation.MANDATORY)
    public void mandatory() {
        userRepository.save(new User("Eve"));
        // Если нет активной транзакции → исключение!
    }
    
    // 6. NEVER — транзакция НЕ должна быть
    @Transactional(propagation = Propagation.NEVER)
    public void never() {
        userRepository.save(new User("Frank"));
        // Если есть активная транзакция → исключение!
    }
}

Сценарий: Как REQUIRED объединяет транзакции

@Service
public class OrderProcessingService {
    
    @Autowired
    private OrderService orderService;
    
    @Autowired
    private NotificationService notificationService;
    
    @Autowired
    private LoggingService loggingService;
    
    // Главная транзакция
    @Transactional
    public void processCompleteOrder(OrderRequest request) {
        // ─────────── ОДНА ТРАНЗАКЦИЯ ───────────
        // BEGIN TRANSACTION
        
        // 1. orderService.create() — REQUIRED
        // → использует СУЩЕСТВУЮЩУЮ транзакцию
        Order order = orderService.create(request);
        
        // 2. notificationService.notify() — REQUIRED
        // → использует ТУ ЖЕ транзакцию
        notificationService.notify(order);
        
        // 3. loggingService.log() — REQUIRED
        // → использует ТУ ЖЕ транзакцию
        loggingService.log("Order created: " + order.getId());
        
        // COMMIT (если всё ОК) или ROLLBACK (если ошибка)
    }
    
    // Если ошибка в любом методе → весь заказ откатывается
}

@Service
public class OrderService {
    @Transactional(propagation = Propagation.REQUIRED)
    public Order create(OrderRequest request) {
        // Используем транзакцию от processCompleteOrder()
        Order order = new Order(request);
        // INSERT
        return order;
    }
}

@Service
public class NotificationService {
    @Transactional(propagation = Propagation.REQUIRED)
    public void notify(Order order) {
        // Используем транзакцию от processCompleteOrder()
        // INSERT в audit_log
    }
}

REQUIRED vs REQUIRES_NEW: различие

@Service
public class ComparisonDemo {
    
    @Transactional
    public void mainTransaction() {
        userRepository.save(new User("User1"));
        
        // REQUIRED: все в одной транзакции
        methodWithRequired();      // Ошибка → откатывает всё
        
        // REQUIRES_NEW: в отдельной транзакции
        methodWithRequiresNew();   // Ошибка → откатывает только эту
    }
    
    @Transactional(propagation = Propagation.REQUIRED)
    public void methodWithRequired() {
        userRepository.save(new User("User2"));
        throw new RuntimeException("Error!");
        // Результат: User1 и User2 НЕ сохраняются (откат всей транзакции)
    }
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void methodWithRequiresNew() {
        userRepository.save(new User("User3"));
        throw new RuntimeException("Error!");
        // Результат: User1 сохраняется, User3 НЕ сохраняется
    }
}

Таблица всех значений Propagation

ЗначениеПоведениеОшибка если нет транзакции
REQUIREDИспользуй существующую или создай новуюНет, создаст новую
REQUIRES_NEWВсегда создай новуюНет, создаст новую
SUPPORTSИспользуй если есть, иначе — безНет, работает без
NOT_SUPPORTEDНе используй транзакциюНет, отключает
MANDATORYДолжна быть обязательноДА, исключение
NEVERНе должно быть транзакцииДА, исключение
NESTEDВложенная транзакция (savepoint)Нет, создаст новую

Когда использовать REQUIRED

// ✅ ИСПОЛЬЗУЙ REQUIRED для:

// 1. Обычных операций с БД
@Transactional(propagation = Propagation.REQUIRED)
public void saveUser(User user) {
    userRepository.save(user);
}

// 2. Когда нужна атомарность группы операций
@Transactional(propagation = Propagation.REQUIRED)
public void transferMoney(Account from, Account to, BigDecimal amount) {
    from.decreaseBalance(amount);
    to.increaseBalance(amount);
    accountRepository.save(from);
    accountRepository.save(to);
    // Либо оба переводы, либо ни один (атомарность)
}

// ❌ НЕ ИСПОЛЬЗУЙ REQUIRED если нужна отдельная транзакция
// Для этого используй REQUIRES_NEW
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void auditLog(String action) {
    // Логирование должно быть независимо от основной операции
}

Заключение

REQUIRED — это режим распространения транзакций по умолчанию в Spring. Он автоматически использует существующую транзакцию или создаёт новую, что делает его идеальным выбором для 90% случаев. Это обеспечивает атомарность и консистентность для группы операций с БД. Выбирайте другие значения propagation только когда нужно специфичное поведение (например, REQUIRES_NEW для независимого логирования).

Что такое REQUIRED в propagation? | PrepBro