Я пытаюсь получить данные и затем обработать эти данные в отдельной транзакции. У меня есть внешний метод (с внешней транзакцией) и внутренний метод (с внутренней транзакцией) для этого.
Наружный это:
@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.