Выгодно ли использовать @Transactional для метода,где есть работа с БД и хранилищем файлов? Если нет,как лучше использовать @Transactional для такого?

У меня есть приложение с использованием Java 11, Spring Boot и Spring Data JPA. В одном из сервисов есть метод по удалению старых файлов. Его работа заключается в физическом удалении файлов из хранилища файлов и потом проставлении в БД каждому файлу метки, что файл был удалён.

Поскольку в рамках этого метода происходит обновление данных в БД, то хотелось бы поинтересоваться, подскажите, пожалуйста, в каком месте лучше использовать @Transactional? У меня сейчас есть 3 идеи:

  1. @Transactional для всего метода deleteObsoleteFiles(), но в таком случае, кажется, транзакция будет открыта недопустимо долго, поскольку в этом же методе ещё будет происходить удаление файлов из хранилища, что может занимать много времени в случае удаления большого количества файлов и походу всё это время транзакция будет оставаться открытой;
  2. Вынести SELECT (получение всех старых файлов из БД) и UPDATE (простановку файла маркера удаления) в отдельные public-методы и для каждого проставить @Transactional. Видится, в таком случае транзакции будут открыты только во время взаимодействия с БД, но не с хранилищем файлов.
  3. Не использовать @Transactional, а выполнить SELECT (получение всех старых файлов из БД) без транзакции, удалить файлы из хранилища и потом выполнить UPDATE без транзакций методом saveAll(), который кажется что на уровне JpaRepository (в классе SimpleJpaRepository над методом saveAll()) имеет @Transactional.

Подскажите, пожалуйста, какой лучше использовать подход в такой ситуации? Псевдокод сервиса прилагаю:

public class CleaningServiceImpl implements CleaningService {
   ...
  @Override
  public void deleteObsoleteFiles() {
    List<FileInfo> obsoleteFiles = findObsoleteFiles(); // получение всех старых файлов из БД
    deleteFiles(obsoleteFiles);
  }

  private void deleteFiles(List<FileInfo> files) {
    if (CollectionUtils.isEmpty(files)) return;
    List<FileInfo> successfullyDeletedFiles = new ArrayList<>();
    files.forEach(
      file -> {
        if (deleteFileFromStorage(file)) successfullyDeletedFiles.add(file);
      });
    markFilesAsDeletedInDb(successfullyDeletedFiles);
  }

  private boolean deleteFileFromStorage(FileInfo file) {
    try {
      // успешное удаление файла из хранилища
      return true;
    } catch (IOException e) {
      // возникло исключение
      log.error("Failed to delete file {}. {}", file.getFileName(), e.getMessage(), e);
    }
    return false;
  }

  private void markFilesAsDeletedInDb(List<FileInfo> files) {
    files.forEach(file -> file.setDeleted(TRUE));
    fileRepository.saveAll(files);
  }
...
}

Ответы (0 шт):