Правильное использование @Transactional в Spring boot для больших запросов

#java #spring-boot #hibernate #transactions #spring-transactions

Вопрос:

У меня есть метод, который вызывает 3 дочерних метода перед совершением транзакции с репозиторием, например :

 import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class ObjectService {

  @Transactional
  public void doSomething() {
    objectRepository.findAllObject();
    childMethod1();
    childMethod2();
    childMethod3();
    objectRepository.save(int id);
  }

  public void childMethod1() { 
    //do something
  } 

  public void childMethod2() { 
    //do something
  } 

  public void childMethod3() { 
    //do something
  } 

}
 

и в репозитории есть метод выбора и сохранения :

 @Query("SELECT * FROM object WHERE id is null")
Optional<Obeject> findAllObject();

@Query("SELECT * FROM object WHERE id is null")
Optional<Obeject> save(int id);
 

В моем случае, если я использую эту систему в таблице со 100 тысячами записей, приложение запускается с выполнения запросов quicl, но транзакция не выполняется (нет перемещения в базе данных), потому что программа, похоже, ожидает выполнения всей работы перед выполнением метода репозитория.

Таким образом, на самом деле, если я использую этот метод для всех записей таблицы, загрузка Spring будет становиться все меньше и меньше и завершится блокировкой без внесения ни одного изменения в базу данных.

Так что, на самом деле, я создал конечную точку для этого с циклом из 1000 элементов. Просто нужно пропинговать его с помощью задания bash, и это работает, но это грязный метод.

Я хотел бы знать, какова наилучшая практика и является ли этот второй способ хорошим методом для вас :

 import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class ObjectService {

  @Transactional(propagation = Propagation.REQUIRES_NEW)
  public void doSomething() {
    objectRepository.findAllObject();
    childMethod1();
    childMethod2();
    childMethod3();
    objectRepository.save(int id);
  }

  public void childMethod1() { 
    //do something
  } 

  public void childMethod2() { 
    //do something
  } 

  public void childMethod3() { 
    //do something
  } 

}
 

Если я правильно понимаю, аннотация

@Транзакционный(распространение = Распространение.REQUIRES_NEW)

будет ли выполнена 1 транзакция в конце выполнения родительского метода для всех объектов, возвращаемых репозиторием, вместо ожидания окончания выполнения для всего объекта, верно?

Извините, если эти вопросы кажутся вам простыми, я пытаюсь понять документацию, но ее трудно понять с плохим уровнем английского языка.

Спасибо за вашу помощь!

ИЗМЕНИТЬ: добавить методы репозитория

Комментарии:

1. Пожалуйста, прочитайте: Могу ли я задать только один вопрос за пост?

2. Это был скорее дополнительный вопрос, но, ладно, я его удалил. 🙂

3. » … выполнит 1 транзакцию в конце выполнения » — Нет. Транзакция открывается в начале @Transactional метода (через перехватчик) и закрывается при возврате метода. Фиксация происходит, когда метод возвращается (опять же, через перехватчик).

4. Хм, это странно, потому что репозиторий ожидает окончания выполнения X-кратного выполнения метода перед записью в базу данных… Возможно ли, что @Transactional совершает фиксацию и ждет окончания всего процесса, чтобы записать их в базу данных с репозиторием?

5. Ах да. Это кое-что объясняет. Таким образом, размер проблемы увеличивается. В этом случае я предполагаю, что транзакция просто «слишком велика» (т. Е. Слишком много строк обновляется). Я бы предложил обрабатывать записи в пакетных размерах. Ваши данные свидетельствуют о том, что размер пакета от 100 до 1000 кажется разумным.