@ Транзакционная аннотация Spring boot 2.0 и спящий режим LazyInitializationException - PullRequest
0 голосов
/ 10 июня 2018

У меня следующий вопрос.Из того, что я понимаю, аннотация @Transactional должна поддерживать сеанс, таким образом, позволяя лениво извлекать дочерние объекты без необходимости выполнения определенного запроса на присоединение.

У меня есть следующий сценарий, в котором я не понимаюпочему я все еще получаю LazyInitializationException.

Мое приложение запускает распознаватель, чтобы обеспечить различные службы контроллера разрешенным объектом, чтобы его можно было использовать напрямую.

Указанный преобразовательперехватывает заголовок из запроса и, используя его значение, пытается запросить базу данных, чтобы получить объект.Теперь рассматриваемый объект довольно прост: он выполняет свои функции, хотя у него есть список из двух суб-сущностей.

Для выполнения действия разрешения я использую дополнительный сервис, в котором я в основном обертываю некоторую JpaRepositoryметоды.Полное описание приведено ниже:

@Service
public class AppClientServiceImpl implements AppClientService {

    private static final Logger LOGGER = LoggerFactory.getLogger(AppClientServiceImpl.class.getCanonicalName());

    private final AppClientRepository repository;

    @Autowired
    public AppClientServiceImpl(AppClientRepository repository) {
    this.repository = repository;
    }

    @Override
    @Transactional(readOnly = true)
    public AppClient getByAppClientId(final String appClientId) {
        LOGGER.debug("Attempting to retrieve appClient with id:: {}", appClientId);
    return repository.findByAppClientId(appClientId);
    }

    @Override
    @Transactional
    public void saveAndFlush(final AppClient appClient) {
        LOGGER.debug("Attempting to save/update appClient:: {}", appClient);
    repository.saveAndFlush(appClient);
    }

}

Как вы можете видеть, оба метода аннотированы как @Transactional, что означает, что они должны поддерживать сеанс в контексте этого указанного метода.

Теперь,мои основные вопросы следующие:

1) Использование отладчика, который я вижу даже на этом уровне getByAppClientId, список, содержащий на ленивых загруженных объектах, был решен просто отлично.

2) На самом распознавателе, где объект был получен от метода делегирования, список не может быть оценен из-за LazyInitializationException.

3) Наконец, в конечном методе обслуживания контроллера, которыйтакже помечен как @Transactional, то же самое, что и выше, означает, что в конечном итоге это не сработает (так как он выполняет получение списка, который не удалось инициализировать.

На основании всего вышеизложенного, я быХотелось бы знать, что является лучшим подходом при обработке этого. На этот раз я не хочу использовать тип извлечения Eager, и я также хотел бы избежать использования запросов извлечения. Также отмечая mПри разрешении на @Transactional, таким образом, сохранение сеанса также не может быть и речи.

Я думал, что, поскольку @Transactional оставит сеанс открытым, что позволит конечному методу обслуживания получитьсписок подразделенийПохоже, что это не так.

Исходя из всего вышесказанного, мне кажется, что мне нужен способ для окончательного метода обслуживания, который получает вызов (которому нужен список под рукой), чтобы каким-то образом получить его.

Какой лучший способ справиться с этим?Я прочитал довольно много постов здесь, но я не могу разобрать, какие методы являются наиболее приемлемыми для Spring boot 2.0 и hibernate 5.

Обновление:

Кажется, что комментирует подпрограмму.предоставьте следующие права:

@ Fetch (FetchMode.SELECT) @LazyCollection (LazyCollectionOption.TRUE)

Решает проблему, но я до сих пор не знаю, является ли это лучшим подходом.

1 Ответ

0 голосов
/ 19 июля 2018

Вы инициализируете коллекцию путем отладки.Отладчик обычно представляет коллекции особым образом, используя методы коллекций, которые запускают инициализацию, поэтому это может быть причиной того, что кажется, что он работает нормально во время отладки.Я полагаю, что распознаватель выходит за рамки getByAppClientId?В этот момент сеанс закрывается, поэтому вы видите исключение.

Я создал Blaze-Persistence Entity Views именно для этого варианта использования.По сути, вы определяете DTO для объектов JPA как интерфейсы и применяете их к запросу.Он поддерживает отображение вложенных DTO, коллекций и т. Д., По сути, всего, что вы ожидаете, и, кроме того, он улучшит производительность ваших запросов, поскольку будет генерировать запросы, извлекающие только те данные, которые вам действительно нужны для DTO.

Виды сущностей для вашего примера могут выглядеть следующим образом

@EntityView(AppClient.class)
interface AppClientDto {
  String getName();
}

Запросы могут выглядеть следующим образом

List<AppClientDto> dtos = entityViewManager.applySetting(
  EntityViewSetting.create(AppClientDto.class),
  criteriaBuilderFactory.create(em, AppClient.class)
).getResultList();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...