1. Обзор
В этом уроке мы увидим, что такое прокси-сервер в контексте метода Hibernate load () .
Для тех читателей, которые не знакомы с гибернацией, подумайте о том, чтобы сначала ознакомиться с основами.
2. Краткое Введение В Прокси-Серверы и Метод load()
По определению, прокси – это “функция, уполномоченная действовать в качестве заместителя или заменять другого” .
Это относится к спящему режиму, когда мы вызываем Session.load() для создания так называемого неинициализированного прокси-сервера желаемого класса сущностей.
Проще говоря, Hibernate подклассы нашего класса сущностей, используя библиотеку CGLib . Кроме метода @Id , реализация прокси делегирует все другие методы свойств сеансу гибернации для заполнения экземпляра, например:
public class HibernateProxy extends MyEntity { private MyEntity target; public String getFirstName() { if (target == null) { target = readFromDatabase(); } return target.getFirstName(); } }
Этот подкласс будет возвращен вместо прямого запроса к базе данных.
Как только вызывается один из методов сущности, сущность загружается и в этот момент становится инициализированным прокси-сервером .
3. Прокси и ленивая загрузка
3.1. Единое Юридическое лицо
Давайте подумаем о Сотруднике как о сущности. Для начала предположим, что он не имеет никакого отношения ни к каким другим таблицам.
Если мы используем Session.load() для создания экземпляра Сотрудника :
Employee albert = session.load(Employee.class, new Long(1));
Затем Hibernate создаст неинициализированный прокси-сервер Employee . Он будет содержать идентификатор, который мы ему дали, но в противном случае не будет иметь других значений, потому что мы еще не попали в базу данных.
Однако, как только мы вызовем метод на albert :
String firstName = albert.getFirstName();
Затем Hibernate запросит таблицу базы данных employee для сущности с первичным ключом 1, заполнив albert его свойствами из соответствующей строки.
Если ему не удается найти строку, то Hibernate выдает исключение ObjectNotFoundException .
3.2. Отношения “Один ко многим”
Теперь давайте также создадим Компанию сущность, в которой Компания имеет много Сотрудников:
public class Company { private String name; private Setemployees; }
Если мы на этот раз используем Session.load() на компании:
Company bizco = session.load(Company.class, new Long(1)); String name = bizco.getName();
Затем свойства компании заполняются, как и раньше, за исключением того, что набор сотрудников немного отличается.
Видите ли, мы запросили только строку компании, но прокси-сервер оставит сотрудника в покое, пока мы не позвоним получить Сотрудников в зависимости от стратегии выборки.
3.3. Отношения “Многие к одному”
Случай похож в противоположном направлении:
public class Employee { private String firstName; private Company workplace; }
Если мы снова используем load() :
Employee bob = session.load(Employee.class, new Long(2)); String firstName = bob.getFirstName();
боб теперь будет инициализирован, и на самом деле, рабочее место теперь будет установлен неинициализированный прокси-сервер в зависимости от стратегии выборки.
4. Ленивая загрузка
Теперь load() не всегда будет давать нам неинициализированный прокси. На самом деле, Session java doc напоминает нам (курсив добавлен):
Этот метод может возвращать проксированный экземпляр, который инициализируется по требованию при обращении к методу без идентификатора.
Простой пример того, когда это может произойти, – это размер пакета.
Допустим, мы используем @BatchSize на нашем Сотруднике объекте:
@Entity @BatchSize(size=5) class Employee { // ... }
И на этот раз у нас трое сотрудников:
Employee catherine = session.load(Employee.class, new Long(3)); Employee darrell = session.load(Employee.class, new Long(4)); Employee emma = session.load(Employee.class, new Long(5));
Если мы вызовем getFirstName on catherine :
String cathy = catherine.getFirstName();
Затем, на самом деле, Hibernate может решить загрузить всех трех сотрудников сразу, превратив всех троих в инициализированные прокси.
А потом, когда мы позовем даррелла по имени:
String darrell = darrell.getFirstName();
Тогда Hibernate вообще не попадает в базу данных.
5. Нетерпеливая загрузка
5.1. Использование get()
Мы также можем полностью обойти прокси-серверы и попросить Hibernate загрузить реальную вещь с помощью Session.get() :
Employee finnigan = session.get(Employee.class, new Long(6));
Это вызовет базу данных сразу же, вместо того, чтобы возвращать прокси-сервер.
И на самом деле, вместо Исключение ObjectNotFoundException , он вернется нулевой если финниган не существует.
5.2. Последствия для производительности
В то время как get() удобен, load() может быть легче в базе данных.
Например, предположим, что Джеральд собирается работать в новой компании:
Employee gerald = session.get(Employee.class, new Long(7)); Company worldco = (Company) session.load(Company.class, new Long(2)); employee.setCompany(worldco); session.save(employee);
Поскольку мы знаем, что в этой ситуации мы собираемся изменить только запись employee , вызов load() для Компании имеет смысл.
Если бы мы позвонили получить() на Компания , тогда мы бы без необходимости загрузили все его данные из базы данных.
6. Заключение
В этой статье мы кратко узнали, как Прокси-серверы Hibernate работают и как это влияет на метод load с сущностями и их отношениями.
Кроме того, мы быстро рассмотрели, чем load() отличается от get().
Как обычно, полный исходный код, сопровождающий учебник, доступен на GitHub.