Hibernate: різниця між session.get і session.load


88

З API я бачив, що це пов’язано з проксі. Але я не зміг знайти багато інформації про проксі і не розумію різниці між дзвінком session.getта session.load. Хтось може пояснити або направити мене на посилальну сторінку?

Дякую!!

Відповіді:


117

З форуму про сплячий режим :

Це з книги Hibernate in Action. Хороший прочитав це ..


Отримання об’єктів за ідентифікатором Наступний фрагмент коду Hibernate отримує об’єкт користувача з бази даних:

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> () повертає проксі!
Кент Бугаарт,

7
Дуже дякую! Грошовою частиною для мене було: "Якщо load () не може знайти об'єкт у кеші чи базі даних, виникає виняток. Метод get () повертає нуль, якщо об'єкт не вдається знайти".
Кріс

15
JavaDoc для Session.get каже: Поверніть постійний екземпляр даного класу сутності із заданим ідентифікатором або нуль, якщо такого постійного екземпляра немає. (Якщо екземпляр або проксі-сервер для екземпляра вже пов’язаний із сеансом, поверніть цей екземпляр або проксі.) Тож розділ із книги, в якому сказано: „З іншого боку, get () ніколи не повертає проксі-сервер“. неправильно.
Вікі

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

Проблема, яку описав @Vicky, може спричинити головний біль, і я не бачу в ній жодної переваги. У деяких випадках мені додатково потрібен ідентифікатор для подальших параметризованих запитів. Але оскільки проксі-сервер об'єкта вже перебуває у сеансі, отримувач ідентифікатора повертає значення null. Чому вони отримують проксі замість реального екземпляра, якщо цей проксі знаходиться у сеансі?
djmj

15

Ну, принаймні в nhibernate, session.Get (id) завантажить об'єкт з бази даних, тоді як session.Load (id) лише створює йому проксі-об'єкт, не виходячи з вашого сервера. Працює так само, як і будь-яке інше властивість, яке завантажується ліниво у ваших POCO (або POJO :). Потім ви можете використовувати цей проксі як посилання на сам об’єкт для створення зв’язків тощо.

Подумайте про це, як про наявність об’єкта, який зберігає лише ідентифікатор, і який завантажить решту, якщо вам коли-небудь знадобиться. Якщо ви просто передаєте його для створення стосунків (наприклад, FK), ідентифікатор - це все, що вам коли-небудь знадобиться.


отже, ви хочете сказати, що load (id) спочатку потрапить у базу даних, щоб перевірити, чи є дійсним id, чи ні, а потім поверне об’єкт-проксі, а коли доступ до властивостей цього об’єкта знову потрапляє в базу даних? хіба це малоймовірний сценарій? два запити для завантаження одного об’єкта?
faisalbhagat

Ні, load (id) взагалі не перевіряє ідентифікатор, тому немає об’їздів до БД. Використовуйте його лише тоді, коли переконаєтесь, що він дійсний.
Хорхе Алвес

9

session.load () завжди повертає "проксі" (термін Hibernate), не потрапляючи в базу даних. У сплячому режимі проксі - це об’єкт із заданим значенням ідентифікатора, його властивості ще не ініціалізовані, він просто виглядає як тимчасовий фальшивий об’єкт. Якщо жодного рядка не знайдено, він викличе ObjectNotFoundException.

session.get () завжди потрапляє в базу даних і повертає реальний об'єкт, об'єкт, який представляє рядок бази даних, а не проксі. Якщо рядок не знайдено, він повертає значення null.

Ефективність цих методів також різниться. між двома ...


3

Ще одна зайва точка:

get метод класу Hibernate Session повертає null, якщо об'єкт не знайдено в кеші, а також у базі даних. в той час як метод load () викидає ObjectNotFoundException, якщо об’єкт не знайдено в кеші, а також у базі даних, але ніколи не повертає null.


2

Одним непрямим наслідком використання "load" замість "get" є те, що оптимістичне блокування за допомогою атрибута version може не працювати, як ви очікували. Якщо навантаження просто створює проксі-сервер і не читає з бази даних, властивість версії не завантажується. Версія буде завантажена лише тоді, коли / якщо ви пізніше посилаєтесь на властивість об'єкта, викликаючи вибір. Тим часом інший сеанс може оновити об’єкт, і ваш сеанс не матиме оригінальної версії, яка йому потрібна для оптимістичної перевірки блокування, тому оновлення сеансу замінить оновлення іншої сесії без попередження.

Ось спроба намалювати цей сценарій із двома сеансами, що працюють з об’єктом з однаковим ідентифікатором. Початкова версія об'єкта в БД - 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 негайно видасть вибір, а номери версій будуть завантажені в потрібний час для оптимістичної перевірки блокування.


0

Також ми повинні бути обережними під час використання load, оскільки це викличе виняток, якщо об'єкта немає. Ми повинні використовувати його лише тоді, коли впевнені, що об’єкт існує.


0

Прекрасне пояснення можна знайти за адресою http://www.mkyong.com/hibernate/different-between-session-get-and-session-load
session.load ():
воно завжди повертає "проксі" (термін сплячого режиму) без потрапляння в базу даних.
У сплячому режимі проксі - це об’єкт із заданим значенням ідентифікатора, його властивості ще не ініціалізовані, він просто виглядає як тимчасовий фальшивий об’єкт. Він завжди потрапляє в базу даних (якщо її не знайти в кеші) і повертає реальний об'єкт, об'єкт, який представляє рядок бази даних, а не проксі. Якщо рядок не знайдено, він повертає значення null.
Він завжди повертає об'єкт-проксі із заданим значенням ідентичності, навіть значення ідентичності не існує у базі даних. Однак при спробі ініціалізувати проксі, отримавши його властивості з бази даних, він потрапить у базу даних із оператором select. Якщо не знайдено жодного рядка, викине ObjectNotFoundException.
session.get ():



0

load () не може знайти об'єкт з кешу чи бази даних, викидається виняток і метод load () ніколи не повертає значення null.

метод get () повертає значення null, якщо об’єкт не вдається знайти. Метод load () може повертати проксі замість реального постійного екземпляра get () ніколи не повертає проксі.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.