Внутренняя транзакция, влияющая на внешнюю транзакцию в Spring Boot - PullRequest
0 голосов
/ 22 апреля 2020

Я пытаюсь получить данные и затем обработать эти данные в отдельной транзакции. У меня есть внешний метод (с внешней транзакцией) и внутренний метод (с внутренней транзакцией) для этого.

Наружный это:

@Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
public void work() {
    Stream<Item> itemStream = itemRepo.streamAll();
    try {
        List<Object> list = itemStream
                .map(item -> secondService.processItem(item))
                .collect(Collectors.toList());
        System.out.println(list);
    } catch (Exception e) {
        System.err.println("outer");
        e.printStackTrace();
    }
    itemRepo.findAll().forEach(System.out::println);
}

и внутренний это:

@Transactional(propagation = Propagation.REQUIRES_NEW)
public Integer processItem(Item item) {
    try {
        if (item.getId() == 2) {
            //content
        }
        itemRepo.save(item);
        itemRepo.flush();
        return 0;
    } catch (Exception e) {
        System.err.println("failed");
        return 1;
    }
}

Итак, у меня есть отдельная транзакция для внутренней части.

Допустим, у меня есть 3 элемента в потоке (и средний - с id=2) Если часть //content заменена на что-то, что вызывает исключение RuntimeException (например, throw new RuntimeException("inner");), затем обрабатываются все элементы (включая третий, следующий за id=2 one). Если часть //content выдает DataIntegrityViolationException (например, пытается установить значение null в поле NOT NULL), то это исключение каким-то образом распространяется на внешнюю транзакцию, и я вижу

org.springframework.transaction.UnexpectedRollbackException: Transaction silently rolled back because it has been marked as rollback-only

в части catch метода work. (и поскольку исключение было передано во внешний метод, третий элемент в потоке не обрабатывается).

Что здесь происходит? Разве метод processItem не должен перехватывать все исключения, и ничто не должно откатывать внешнюю транзакцию?

Есть ли способ применить этот шаблон другим способом? Обрабатывать элементы потока совершенно независимо от других элементов в отдельной транзакции? Я использую Hibernate, поэтому я не могу использовать NESTED аннотацию. Не уверен, что это актуально, но базовая база данных Postgres.

...