Hibernate: разница между session.get и session.load


88

Из API я понял, что это как-то связано с прокси. Но я не смог найти много информации о прокси и не понимаю разницы между вызовом session.getи session.load. Может ли кто-нибудь объяснить или направить меня на справочную страницу?

Спасибо!!

Ответы:


117

Из форума Hibernate :

Это из книги Hibernate in Action. Хороший читал это ..


Получение объектов по идентификатору Следующий фрагмент кода Hibernate извлекает объект User из базы данных:

User user = (User) session.get(User.class, userID);

Метод get () особенный, потому что идентификатор однозначно определяет отдельный экземпляр класса. Следовательно, приложения обычно используют идентификатор как удобный дескриптор постоянного объекта. Получение по идентификатору может использовать кеш при извлечении объекта, избегая попадания в базу данных, если объект уже кэширован. Hibernate также предоставляет метод load ():

User user = (User) session.load(User.class, userID);

Метод load () старше; get () был добавлен в API Hibernate по запросу пользователя. Разница банальна:

Если load () не может найти объект в кеше или базе данных, генерируется исключение. Метод load () никогда не возвращает значение null. Метод get () возвращает null, если объект не может быть найден.

Метод load () может возвращать прокси вместо реального постоянного экземпляра. Прокси-сервер - это заполнитель, который запускает загрузку реального объекта при первом обращении к нему; С другой стороны, get () никогда не возвращает прокси. Выбор между get () и load () прост: если вы уверены, что постоянный объект существует, а его несуществование будет считаться исключительным, load () - хороший вариант. Если вы не уверены, что существует постоянный экземпляр с данным идентификатором, используйте get () и проверьте возвращаемое значение, чтобы убедиться, что оно равно нулю. Использование load () имеет еще одно значение: приложение может получить действительную ссылку (прокси) на постоянный экземпляр, не обращаясь к базе данных для получения ее постоянного состояния. Таким образом, load () может не генерировать исключение, если не находит постоянный объект в кэше или базе данных; исключение будет выброшено позже при доступе к прокси. Конечно, получение объекта по идентификатору не так гибко, как использование произвольных запросов.


1
Я сейчас отлаживаю проблему, когда session.Get <T> () возвращает прокси!
Kent Boogaart

7
Большое спасибо! Денежная часть для меня была: «Если load () не может найти объект в кеше или базе данных, генерируется исключение. Метод get () возвращает null, если объект не может быть найден».
Крис

15
В JavaDoc для Session.get говорится: «Верните постоянный экземпляр данного класса сущности с заданным идентификатором или null, если такого постоянного экземпляра нет». (Если экземпляр или прокси для экземпляра уже связан с сеансом, верните этот экземпляр или прокси.) Итак, раздел из книги, в котором говорится: «С другой стороны, get () никогда не возвращает прокси». не является правильным.
Вики

если вы используете стратегию управления транзакциями со своим daos, вы можете предпочесть get (). в противном случае вызывающий должен будет также выполняться в контексте открытого сеанса гибернации, если load () возвращает прокси. например, если вы выполняете MVC, ваш контроллер может выполнить dao.load () и затем выдать исключение при попытке доступа к прокси-объекту позже, если нет действительного сеанса. выполнение dao.get () вернет фактический объект контроллеру независимо от сеанса (при условии, что он существует)
dev

Проблема, описанная @Vicky, может вызвать головную боль, и я не вижу в этом никакой пользы. В некоторых случаях мне дополнительно нужен идентификатор для дальнейших параметризованных запросов. Но поскольку прокси объекта уже находится в сеансе, получатель идентификатора возвращает null. Почему они извлекают прокси вместо реального экземпляра, если этот прокси находится в сеансе?
djmj 05

15

Ну, по крайней мере, в nhibernate, session.Get (id) загрузит объект из базы данных, а session.Load (id) только создает для него прокси-объект, не покидая ваш сервер. Работает так же, как и любое другое свойство с отложенной загрузкой в ​​ваших POCO (или POJO :). Затем вы можете использовать этот прокси как ссылку на сам объект для создания отношений и т. Д.

Думайте об этом как об объекте, который хранит только Id и который загрузит все остальное, если вам когда-нибудь понадобится. Если вы просто передаете его для создания отношений (например, FK), идентификатор - это все, что вам когда-либо понадобится.


поэтому вы хотите сказать, что load (id) сначала попадет в базу данных, чтобы проверить, является ли он действительным идентификатором или нет, а затем вернет прокси-объект, и когда свойства этого объекта будут доступны, он снова попадет в базу данных? Разве это не маловероятный сценарий? два запроса на загрузку одного объекта?
faisalbhagat

Нет, load (id) не будет проверять идентификатор вообще, поэтому никаких обратных обращений к БД. Используйте его только тогда, когда уверены, что он действителен.
Хорхе Алвес

9

session.load () всегда будет возвращать «прокси» (термин Hibernate), не обращаясь к базе данных. В Hibernate прокси - это объект с заданным значением идентификатора, его свойства еще не инициализированы, он просто выглядит как временный поддельный объект. Если строка не найдена, генерируется исключение ObjectNotFoundException.

session.get () всегда обращается к базе данных и возвращает реальный объект, объект, представляющий строку базы данных, а не прокси. Если строка не найдена, возвращается значение null.

Производительность с этими методами также влияет на разницу. между двумя ...


3

Еще один дополнительный балл:

Метод get класса Hibernate Session возвращает null, если объект не найден в кеше, а также в базе данных. в то время как метод load () генерирует исключение ObjectNotFoundException, если объект не найден в кеше, а также в базе данных, но никогда не возвращает значение null.


2

Одним из косвенных последствий использования load вместо get является то, что оптимистическая блокировка с использованием атрибута версии может работать не так, как вы ожидали. Если загрузка просто создает прокси и не считывает данные из базы данных, свойство версии не загружается. Версия будет загружена только тогда, когда / если вы позже обратитесь к свойству объекта, инициируя выбор. Тем временем другой сеанс может обновить объект, и у вашего сеанса не будет исходной версии, необходимой для выполнения оптимистической проверки блокировки, поэтому обновление вашего сеанса перезапишет обновление другого сеанса без предупреждения.

Вот попытка набросать этот сценарий с двумя сеансами работы с объектом с одним и тем же идентификатором. Начальная версия для объекта в БД - 10.

Session 1                  Session 2
---------                  ---------
Load object
Wait a while..   
                           Load object
                           Modify object property
                           [triggers db 'select' -
                            version read as 10]
                           Commit
                           [triggers db update,
                            version modified to 11]
Modify object property
  [triggers db 'select' -
  version read as 11]
Commit
  [triggers db update,
  version modified to 12]

На самом деле мы хотим, чтобы фиксация сеанса 1 завершилась ошибкой с оптимистичным исключением блокировки, но здесь она будет успешной.

Использование «get» вместо «load» позволяет обойти проблему, потому что get немедленно выполнит выбор, и номера версий будут загружены в правильное время для оптимистической проверки блокировки.


0

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


0

Отличное объяснение можно найти на http://www.mkyong.com/hibernate/different-between-session-get-and-session-load
session.load ():
он всегда будет возвращать «прокси» (термин Hibernate) без попадание в базу данных.
В Hibernate прокси - это объект с заданным значением идентификатора, его свойства еще не инициализированы, он просто выглядит как временный поддельный объект.
Он всегда будет возвращать прокси-объект с заданным значением идентификатора, даже если значение идентификатора не существует в базе данных. Однако, когда вы пытаетесь инициализировать прокси, извлекая его свойства из базы данных, он попадет в базу данных с помощью оператора select. Если строка не найдена, генерируется исключение ObjectNotFoundException.
session.get ():
Он всегда попадает в базу данных (если не найден в кеше) и возвращает реальный объект, объект, представляющий строку базы данных, а не прокси.
Если строка не найдена, возвращается значение null.


0

load () не может найти объект в кеше или базе данных, возникает исключение, и метод load () никогда не возвращает null.

get () метод возвращает null, если объект не может быть найден. Метод load () может возвращать прокси вместо реального постоянного экземпляра. Get () никогда не возвращает прокси.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.