Выгодно ли использовать @Transactional для метода,где есть работа с БД и хранилищем файлов? Если нет,как лучше использовать @Transactional для такого?
У меня есть приложение с использованием Java 11, Spring Boot и Spring Data JPA. В одном из сервисов есть метод по удалению старых файлов. Его работа заключается в физическом удалении файлов из хранилища файлов и потом проставлении в БД каждому файлу метки, что файл был удалён.
Поскольку в рамках этого метода происходит обновление данных в БД, то хотелось бы поинтересоваться, подскажите, пожалуйста, в каком месте лучше использовать @Transactional? У меня сейчас есть 3 идеи:
- @Transactional для всего метода deleteObsoleteFiles(), но в таком случае, кажется, транзакция будет открыта недопустимо долго, поскольку в этом же методе ещё будет происходить удаление файлов из хранилища, что может занимать много времени в случае удаления большого количества файлов и походу всё это время транзакция будет оставаться открытой;
- Вынести SELECT (получение всех старых файлов из БД) и UPDATE (простановку файла маркера удаления) в отдельные public-методы и для каждого проставить @Transactional. Видится, в таком случае транзакции будут открыты только во время взаимодействия с БД, но не с хранилищем файлов.
- Не использовать @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);
}
...
}