Я много гуглил, и это действительно странно, что Spring Boot (последняя версия) может не иметь ленивой загрузки, которая не работает. Ниже приведены фрагменты моего кода:
Мой ресурс:
public ResponseEntity<Page<AirWaybill>> searchAirWaybill(CriteraDto criteriaDto, @PageableDefault(size = 10) Pageable pageable{
airWaybillService.searchAirWaybill(criteriaDto, pageable);
return ResponseEntity.ok().body(result);
}
Мой сервис:
@Service
@Transactional
public class AirWaybillService {
//Methods
public Page<AirWaybill> searchAirWaybill(AirWaybillCriteriaDto searchCriteria, Pageable pageable){
//Construct the specification
return airWaybillRepository.findAll(spec, pageable);
}
}
Моя сущность:
@Entity
@Table(name = "TRACKING_AIR_WAYBILL")
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property = "@airWaybillId") //to fix Infinite recursion with LoadedAirWaybill class
public class AirWaybill{
//Some attributes
@NotNull
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "FK_TRACKING_CORPORATE_BRANCH_ID")
private CorporateBranch corporateBranch;
}
И при отладке я все еще получаю все ленивые загруженные атрибуты загруженных. См. изображение ниже.
Один из моих вопросов: мог ли Джексон быть причастен к такому поведению? Есть ли способ, которым я мог пропустить, чтобы активировать ленивую загрузку?
РЕДАКТИРОВАТЬ
Еще вопрос, мог ли отладчик быть причастен к испорченной ленивой загрузке?
Обновлено еще раз:
Для сборки Технические характеристики у меня есть:
public static Specification<AirWaybill> isBranchAirWayBill(long id){
return new Specification<AirWaybill>() {
@Override
public Predicate toPredicate(Root<AirWaybill> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.equal(root.join("corporateBranch",JoinType.LEFT).get("id"),id);
}
};
}
На службе. я обновил вопрос
Есть ли в ваших критериях какие-либо условия для CorporateBranch? Если да, то как вы создаете спецификацию, переданную в репозиторий?
Да, но условно и даже я убрал спецификацию и загрузил только страницу но все равно вижу проблему
Просто чтобы отбросить проблему, связанную с отладчиком, включите ведение журнала SQL-запросов Spring Boot: stackoverflow.com/questions/30118683/…




При использовании отладчика вы пытаетесь получить доступ к значению ваших переменных. Итак, в тот момент, когда вы нажимаете на эту маленькую стрелку на экране, значение рассматриваемой переменной (лениво) загружается.
Спасибо. Но еще до того, как я нажму на стрелку, я вижу в строке того атрибута, в котором уже есть информация
IDE обрабатывают отладку по-разному. InteliJ загружает для вас все заранее, а другая IDE может и нет.
Скорее всего, вы отлаживаете, все еще находясь внутри службы, поэтому, пока транзакция все еще активна, может быть запущена ленивая загрузка (любой метод, вызванный для ленивого элемента, инициировал выборку из базы данных).
Проблема в том, что отложенная загрузка не может происходить вне транзакции. И Джексон анализирует вашу сущность определенно за пределами одной.
Вы должны либо получить все необходимые зависимости при создании спецификации, либо попробовать использовать @Transactional на уровне ресурсов (но попробуйте это в крайнем случае).
Просто чтобы вы знали, стратегия ЛЕНИВОЙ выборки — это всего лишь подсказка, а не обязательное действие. Стремление обязательно:
The LAZY strategy is a hint to the persistence provider runtime that data should be fetched lazily when it is first accessed. The implementation is permitted to eagerly fetch data for which the LAZY strategy hint has been specified.
Даже когда я вижу ответ в своем браузере, я вижу, что все лениво загруженные атрибуты загружены (что мне не нравится). Так что отладчик не имеет ничего общего с загруженными дочерними элементами.
проверьте мое обновление.
Просто предположение: вы форсируете выборку при построении спецификации.
Я ожидаю что-то вроде
static Specification<AirWaybill> buildSpec() {
return (root, query, criteriaBuilder) -> {
Join<AirWaybill, CorporateBranch> br = (Join) root.fetch("corporateBranch");
return criteriaBuilder.equal(br.get("addressType"), 1);
};
}
Если это так, попробуйте изменить root.fetch на root.join
Спасибо за ваше уведомление, пожалуйста, смотрите обновленное выше
SpringBoot по умолчанию включил:
spring.jpa.open-in-view = правда
Это означает, что транзакция всегда открыта. Попробуйте отключить его.
дополнительная информация здесь
Хорошая помощь, теперь я получаю org.hibernate.LazyInitializationException: could not initialize proxy - no Session. Я пытался установить Hibernate5Module, но пока не получилось, все та же ошибка
Вы можете исправить это с помощью @Transactional. См. ответ Ковальски.
Извлеченные данные уже ленивы, но вы используете режим отладки, его возвращаемое значение при нажатии для просмотра данных из отладчика.
добавьте такой ответ в комментарии.
Сессия гибернации существует в методе с @Transactional.
Передача объекта за пределы класса обслуживания — плохая практика, потому что сеанс закрывается после выхода из вашего метода search. С другой стороны, ваша сущность содержит ленивые инициализированные коллекции, которые нельзя извлечь после закрытия сеанса.
Хорошей практикой является сопоставление сущности с транспортным объектом и возврат этих транспортных объектов из службы (а не необработанных сущностей).
точно лаконично и понятно
Извините, но я этого не понимаю. У вас есть пример, показывающий, как настроен этот транспортный дизайн? заранее спасибо
Пожалуйста, создайте простой POJO (скажем, AirWaybillTO и поместите туда все необходимые атрибуты, затем сопоставьте их с AirWaybill и верните AirWaybillTO из вашего сервиса.
Вы можете решить эту проблему с помощью 2 шагов с Джексон-тип-данных-спящий режим:
kotlin example
build.gradle.kts:implementation("com.fasterxml.jackson.datatype:jackson-datatype-hibernate5:$jacksonHibernate")
@Bean @Bean
fun hibernate5Module(): Module = Hibernate5Module()
Обратите внимание, что Module — это com.fasterxml.jackson.databind.Module, а не java.util.Module
Я также столкнулся с той же проблемой с данными Spring JPA. Я добавил приведенную ниже аннотацию и смог получить записи о клиентах для данного ИДЕНТИФИКАТОРА ЗАКАЗА.
Клиент для заказа: один ко многим
Заказ клиенту является ленивой загрузкой.
Заказ.java
@ManyToOne(cascade = CascadeType.ALL,targetEntity = CustomerEntity.class,fetch = FetchType.LAZY)
@Fetch(FetchMode. JOIN)
@JoinColumn(name = "CUSTOMER_ID",referencedColumnName = "CUSTOMER_ID",insertable = false,updatable = false)
@LazyToOne(LazyToOneOption.PROXY)
Private CustomerEntity customer
Клиент.java
@Entity
@TabLe(name = "CUSTOMER" ,
uniqueConstraints = @UniqueConstraint(columnNames= {"mobile"}))
public class CustomerEntity {
@GeneratedVaLue(strategy = GenerationType.IDENTITY)
@CoLumn(name = "customer_id" )
private Integer customerld;
private String name;
private String address;
private String city;
private String state;
private Integer zipCode;
private Integer mobileNumber;
@OneToMany(mappedBy = " customer" )
@Fetch(FetchMode.JOIN)
@LazyToOne(LazyToOneOption.PROXY)
private List<OrderEntity> orders;
}
Добавьте код и данные в виде текста (с помощью форматирования кода), а не изображений. Изображения: A) не позволяйте нам копировать и вставлять код/ошибки/данные для тестирования; Б) не разрешать поиск по коду/ошибке/содержимому данных; и еще много причин. Изображения следует использовать в дополнение к тексту в формате кода только в том случае, если изображение добавляет что-то важное, что не передается только текстовым кодом/ошибкой/данными.
может кто-нибудь объяснить эту аннотацию. в документации это не объяснено должным образом. baeldung.com/hibernate-lazy-loading-обходной путь после прочтения этой статьи кажется, что @ Transactional лучше, но если мы добавим «enable_lazy_load_no_trans», тогда он вызовет список объектов и каждого объекта, на который ссылается ленивый объект, в одной транзакции для каждого объекта. Будет ли @LazyToOne также выполнять одну транзакцию один раз или это всего лишь один дополнительный txn?
Еще одно соображение заключается в том, что при использовании Lombok аннотация @Data/@Getter приводит к загрузке ленивых элементов без необходимости. Так что будьте осторожны при использовании Ломбока.
Это был мой случай.
где настроен транзакционный? на ресурсе или сервисе?