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

Что такое propagation level в Spring Data?

2.0 Middle🔥 201 комментариев
#Spring Boot и Spring Data#Spring Framework

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

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

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

Propagation Level в Spring Data (Транзакции)

Propagation level (уровень распространения) — это настройка, определяющая как транзакция ведёт себя при вложенных вызовах методов, помеченных @Transactional. Это критично для управления границами транзакций в многоуровневых приложениях.

Основные режимы распространения

REQUIRED (по умолчанию)

  • Использует текущую транзакцию если она существует
  • Создаёт новую если транзакции нет
  • Наиболее часто используемый режим
@Service
public class OrderService {
    @Autowired
    private OrderRepository orderRepository;
    @Autowired
    private PaymentService paymentService;
    
    @Transactional(propagation = Propagation.REQUIRED)
    public Order createOrder(Order order) {
        Order saved = orderRepository.save(order);
        // paymentService тоже работает в этой же транзакции
        paymentService.processPayment(saved);
        return saved;
    }
}

@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);
    }
}

REQUIRES_NEW

  • ВСЕГДА создаёт новую транзакцию
  • Suspend текущей транзакции (если была)
  • Используется когда нужна независимость
@Service
public class OrderService {
    @Autowired
    private OrderRepository orderRepository;
    @Autowired
    private AuditService auditService;
    
    @Transactional(propagation = Propagation.REQUIRED)
    public Order createOrder(Order order) {
        Order saved = orderRepository.save(order);
        // ТРЕБУЕТ_NEW — даже если ошибка здесь, audit сохранится
        auditService.logOrderCreation(saved);
        return saved;
    }
}

@Service
public class AuditService {
    @Autowired
    private AuditRepository auditRepository;
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void logOrderCreation(Order order) {
        // Независимая транзакция
        // Коммитится ОТДЕЛЬНО от createOrder
        Audit audit = new Audit("ORDER_CREATED", order.getId());
        auditRepository.save(audit);
    }
}

SUPPORTED

  • Использует текущую транзакцию если она есть
  • Работает БЕЗ транзакции если её нет
  • Гибкий режим для read-only операций
@Transactional(propagation = Propagation.SUPPORTED, readOnly = true)
public List<Order> getOrders() {
    // Если вызвано из @Transactional метода — работает в этой транзакции
    // Если вызвано как обычный метод — работает БЕЗ транзакции
    return orderRepository.findAll();
}

NOT_SUPPORTED

  • НЕ использует транзакцию
  • Suspend текущей транзакции
  • Используется редко, для операций которые не должны быть transactional
@Transactional
public void mainTransaction() {
    orderRepository.save(order);
    // Эта операция вне транзакции
    notTransactionalOperation();
}

@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void notTransactionalOperation() {
    // Текущая транзакция будет suspended
}

MANDATORY

  • ТРЕБУЕТ существования транзакции
  • Выбросит исключение если нет
  • Используется для критических операций
@Transactional(propagation = Propagation.MANDATORY)
public void onlyInTransaction() {
    // Если вызвано БЕЗ транзакции — IllegalTransactionStateException
    // Гарантирует что метод ВСЕГДА в транзакции
    database.update(data);
}

NEVER

  • ЗАПРЕЩАЕТ транзакцию
  • Выбросит исключение если транзакция активна
  • Противоположность MANDATORY

NESTED

  • Использует savepoints внутри существующей транзакции
  • Позволяет откатить часть логики БЕЗ отката всего
@Transactional
public void mainOperation() {
    save(data1);
    try {
        nestedOperation(); // Может откатиться независимо
    } catch (Exception e) {
        // data1 остался, data2 откатился
    }
}

@Transactional(propagation = Propagation.NESTED)
public void nestedOperation() {
    save(data2); // Savepoint
}

Практические примеры

// User Service — основная логика
@Service
public class UserService {
    @Transactional(propagation = Propagation.REQUIRED)
    public User registerUser(UserRegisterRequest req) {
        User user = new User(req);
        userRepository.save(user);
        
        // Отправка email в отдельной транзакции (может упасть)
        emailService.sendWelcomeEmail(user);
        
        // Логирование в отдельной транзакции (всегда должна быть)
        auditService.logRegistration(user);
        
        return user;
    }
}

// Email Service — может отдельно откатиться
@Service
public class EmailService {
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void sendWelcomeEmail(User user) {
        // Даже если упадёт, user уже в БД
    }
}

// Audit Service — всегда записывает
@Service
public class AuditService {
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void logRegistration(User user) {
        // Независимая запись
    }
}

Выбор правильного уровня

  • REQUIRED — стандарт, используй по умолчанию
  • REQUIRES_NEW — когда нужна независимость (audit, notifications)
  • SUPPORTED — для read-only операций
  • MANDATORY/NEVER — для enforcing constraints
  • NESTED — редко, когда нужны savepoints

Неправильный выбор уровня может привести к deadlocks, несогласованности данных или потере изменений.