Hibernate 3.6 - session.get() vs session.load()

Я пытаюсь понять, в чем разница в возвращаемом объекте и поведении Hibernate 3.6 session.get() и session.load().

Из javadoc:

get():

Возвращает постоянный экземпляр данного класса сущности с помощью данный идентификатор или нуль, если такой постоянный экземпляр отсутствует. (Если экземпляр уже связан с сеансом, возвратите его пример. Этот метод никогда не возвращает неинициализированный экземпляр.)

load():

Возвращает постоянный экземпляр данного класса сущности с помощью данный идентификатор, предполагая, что экземпляр существует. Этот метод может верните экземпляр прокси, который инициализируется по требованию, когда неидентификатор.

У меня есть три вопроса:

  • javadoc не говорит, когда load() может вернуть прокси-сервер - есть ли способ узнать его заранее?

  • Когда load() возвращает прокси - это означает, что load() не получил доступ к базе данных, правильно ли я прав? Тогда что, если я предоставил load() идентификатор, который не существует в базе данных? Теперь у меня будет сеанс прокси с недопустимым идентификатором (без получения исключения). Теперь я хочу, чтобы другой постоянный экземпляр указывал на этот прокси - будет ли он работать? Для этого сценария мне не нужно инициализировать прокси, мне нужен только его идентификатор (который у меня даже несмотря на то, что он недействителен, так как он не находится в базе данных). Поэтому я предполагаю, что я спрашиваю, правильно ли написано мое описание, и всегда нужно проверить после load() возвращаемый объект с isInitialized(), чтобы убедиться, что он представляет действительную сущность (или, по крайней мере, действительный прокси) т.е. с допустимым идентификатором.

  • Кроме того, что произойдет, если load() возвращает прокси-сервер, поэтому прокси-сервер является экземпляром, который уже связан с сеансом. Затем в соответствии с описанием get(): "Если экземпляр уже связан с сеансом, верните этот экземпляр". - так что get() возвращает прокси? Поскольку в соответствии с описанием get(): "Этот метод никогда не возвращает неинициализированный экземпляр".

Спасибо!

UPDATE

Правильны ли следующие?

(A) Я думаю, что как load(), так и get() сначала попытаются проверить кеш сеанса перед тем, как перейти к БД, поэтому было бы неправильно сказать, что любой из них всегда попадает в БД или всегда возвращает прокси.

(B) Инициализированный прокси не совпадает с исходным экземпляром, как вы можете прочитать здесь: http://blog.xebia.com/2008/03/08/advanced-hibernate-proxy-pitfalls/

Ответ 1

(1), (3):

Да. Вы правы. Но сначала load() и get() будут проверять наличие экземпляра с тем же PK в сеансе.

Если да, просто возвращает этот экземпляр из сеанса. (Это может быть прокси или фактический экземпляр класса объекта)

Если нет, load() создаст и вернет прокси-сервер, а get() ударит DB и вернет экземпляр фактического класса сущности.

Возвращаемый объект из обоих методов будет связан и сохранен в сеансе впоследствии.

Итак, возвращает ли get() или load() прокси-сервер или фактический класс сущности зависит от того, используете ли вы get() или load(), чтобы получить экземпляр того же PK в текущем сеансе в первый раз.

Вы можете подтвердить это поведение, выполнив следующий тест:

Session session = HibernateUtil.getSessionFactory().openSession();

Item loadItem= (Item ) session.load(Item.class, 1);
System.out.println(loadItem.getClass().getName());

Item getItem = (Item ) session.get(Item .class, 1);
System.out.println(getItem .getClass().getName());

Если это прокси-сервер, имя печатного класса не будет таким же, как имя класса сущности. Просто измените порядок выполнения на load() и get(), чтобы увидеть эффект.

(2):

Если load() возвращает прокси-сервер, он не будет обращаться к БД во время load(). Прокси будет обращаться к БД только в том случае, если к ним будут применены сопоставленные свойства, кроме ПК, и нет экземпляров с одинаковым значением PK с сеансом.

После того как прокси обратится к БД, экземпляр с тем же PK прокси-сервера будет связан с этим сеансом. Поэтому, когда вы снова получите другие свойства из прокси-сервера или используете get(), чтобы получить экземпляр для той же PK, DB не будет доступен, поскольку значения могут быть найдены из сеанса.

Например:

/**Session starts***/
Item item = (Item) session.load(Item.class, new Long(1));
item.getId();  //Will not access DB as only the identifier property is access
item.getDescription(); // access the DB and initialize the proxy . After that , the item proxy is said to be initialized
item.getPrice(); //will not access DB as the item with the PK 1 can be get from the session
Item item2 = session.get(Item.class, new Long(1)) //will not access DB as the item with the PK 1 can be get from the session

Если вы load() экземпляр с недопустимым идентификатором, а затем получите доступ к свойствам или вызовите метод (например, isInitialized()) в этом прокси, будет выбрано ObjectNotFoundException. Поэтому, если вы можете поймать ObjectNotFoundException, это означает, что прокси загружается с недопустимым идентификатором.

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