Можно ли избежать рекурсии и StackOverflowError в OneToMany-ManyToOne двунаправленных отношениях?

#spring-boot #debugging #recursion #one-to-many #many-to-one

#весенняя загрузка #отладка #рекурсия #один ко многим #многие к одному

Вопрос:

введите описание изображения здесь

Я использую Spring Boot и Thymeleaf для создания веб-приложения.

Когда я отлаживаю свое приложение, оно работает очень МЕДЛЕННО. На каждом шаге F8 отладчик показывает сообщение «Сбор данных …» на моих объектах. И я долгое время не вижу состояния своих объектов (10-60 секунд).

введите описание изображения здесь

Наконец, когда сбор данных завершен, я вижу StackOverflowError.

введите описание изображения здесь

Я понимаю, что в этой ситуации происходит бесконечная рекурсия. Автомобильные ссылки на сервис, сервисные ссылки на автомобиль и так далее. И он переполняет toString() метод для каждого объекта.

Я вижу много примеров использования @OneToMany и @ManyToOne аннотаций. Все они вызывают эту рекурсию и StackOverflowError. И в этом случае инженеры рекомендуют поставить @JsonIgnore или @JsonManagedReference / @JsonBackReference аннотации, чтобы исправить бесконечную рекурсию.

Эти советы отлично работают для сериализованного объекта REST API.

Проблема в том, что я не разрабатываю REST API. Я создаю веб-приложение MVC.

Итак, что вы можете порекомендовать мне, чтобы исправить эту рекурсию и иметь приложение для быстрой отладки?

Это плохой дизайн? Или что-то еще?

Спасибо

Ответ №1:

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

 @ManyToOne(fetch = FetchType.LAZY)
  

это может помочь.

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

1. Ваш ответ полезен. Это частично помогло решить проблему с производительностью во время отладки. Спасибо

Ответ №2:

Рабочее решение проблемы:

  1. Сначала нужно отметить @ManyToOne(fetch = FetchType.LAZY) аннотацию, чтобы повысить производительность при отладке.

  2. Второе, что нужно сделать, это изменить стандартный toString метод, созданный IDE. Для вложенных объектов вы должны возвращать не весь объект, а только идентификатор объекта.

Пример для Service :

Перед модификацией:

 @Override
  public String toString() {
    return "Service{"  
        "serviceId="   serviceId  
        ", car="   car  
        ", event='"   event   '''  
        ", created="   created  
        ", modified="   modified  
        '}';
  }
  

После модификации:

 @Override
  public String toString() {
    String carId;
    if (car == null) {
      carId = "null";
    } else {
      carId = car.getCarId().toString();
    }
    return "Service{"  
        "serviceId="   serviceId  
        ", carId="   carId  
        ", event='"   event   '''  
        ", created="   created  
        ", modified="   modified  
        '}';
  }
  

Теперь я не получаю "Collecting data..." сообщение отладчика и StackOverflowError исключение.

Производительность отладки хорошая!