Представьте себе 2 таблицы в реляционной базе данных, например, Персона и биллинг. Между этими объектами определена (необязательная) связь OneToOne,
Ленивая выборка концептуально невозможна для необязательного OneToOne по умолчанию, Hibernate должен обратиться к базе данных, чтобы узнать, является ли связь null
или нет. Подробнее на этой старой вики-странице:
[...]
Теперь рассмотрим наш класс B
взаимно-однозначная связь с C
class B {
private C cee;
public C getCee() {
return cee;
}
public void setCee(C cee) {
this.cee = cee;
}
}
class C {
// Not important really
}
Сразу после загрузки B вы можете позвонить
getCee()
чтобы получить C. Но посмотрите,
getCee()
- это метод ВАШЕГО класса
и Hibernate не контролирует его.
Hibernate не знает, когда кто-то
собирается позвонить getCee()
. Тот
значит Hibernate должен положить
соответствующее значение в "cee
"
собственность на данный момент загружает B из
база данных. Если прокси включен для
C
, Hibernate может поставить C-прокси
объект, который еще не загружен, но
будет загружен, когда кто-то его использует.
Это дает ленивую нагрузку для
one-to-one
.
Но теперь представьте, что ваш B
объект может или
возможно, не связаны C
(constrained="false"
). Что должно
getCee()
возврат, когда определено B
не C
? Ноль. Но помни,
Hibernate должен установить правильное значение
"cee" в данный момент установлено B
(потому что он не знает, когда кто-то
позвоню getCee()
). Прокси не
здесь помощь, потому что сам прокси в
уже ненулевой объект.
Итак, резюме: если ваше отображение B-> C
является обязательным (constrained=true
),
Hibernate будет использовать прокси для C
приводя к ленивой инициализации. Но
если вы разрешите B без C, Hibernate
просто нужно проверить наличие C на
момент он загружает B. Но ВЫБРАТЬ
проверить наличие просто неэффективно
потому что тот же SELECT может не просто
проверить наличие, но загрузить весь
объект. Так что ленивая загрузка уходит .
Итак, невозможно ... по умолчанию.
Есть ли обходной путь для этого потенциального сбоя производительности (кроме как вообще не использовать общий первичный ключ)? Спасибо за все ваши идеи.
Проблема не в общем первичном ключе, с или без общего первичного ключа, вы получите его, проблема в обнуляемом OneToOne.
Первый вариант : использовать инструментарий байт-кода (см. Ссылки на документацию ниже) и без прокси выборка:
@OneToOne( fetch = FetchType.LAZY )
@org.hibernate.annotations.LazyToOne(org.hibernate.annotations.LazyToOneOption.NO_PROXY)
Второй вариант : Использовать подделку ManyToOne(fetch=FetchType.LAZY)
. Это, наверное, самое простое решение (и, насколько мне известно, рекомендуемое). Но я не проверял это с общим ПК.
Третий вариант : Стремитесь загрузить биллинг, используя join fetch
.
Смежный вопрос
Ссылки
- Справочное руководство по Hibernate
- Старый Hibernate FAQ
- Hibernate Wiki