Прокси в методе загрузки Hibernate ()

Прокси в методе загрузки Hibernate ()

1. обзор

В этом руководстве мы увидим, что такое прокси в контексте методаload() Hibernate.

Для читателей, плохо знакомых с Hibernate, сначала рекомендуется ознакомиться сbasics.

2. Краткое введение в прокси и методload()

By definition, a proxy is “a function authorized to act as the deputy or substitute for another”.

Это относится к Hibernate, когда мы вызываемSession.load() для создания того, что называетсяuninitialized proxy oft, для нашего желаемого класса сущности.

Проще говоря, Hibernate создает подклассы нашего класса сущности, используя библиотекуCGLib. За исключением метода@Id, реализация прокси делегирует все другие методы свойств сеансу Hibernate для заполнения экземпляра, примерно так:

public class HibernateProxy extends MyEntity {
    private MyEntity target;

    public String getFirstName() {
        if (target == null) {
            target = readFromDatabase();
        }
        return target.getFirstName();
    }
}

Этот подкласс будет тем, который будет возвращен вместо прямого запроса базы данных.

После вызова одного из методов сущности сущность загружается и в этот момент становитсяinitialized proxy.

3. Прокси и ленивыйloadпоют

3.1. Единая сущность

Давайте подумаем оEmployee  как о сущности. Для начала предположим, что он не имеет отношения ни к каким другим таблицам.

Если мы используемSession.load() для создания экземпляраEmployee:

Employee albert = session.load(Employee.class, new Long(1));

Затем Hibernate создаст неинициализированный проксиEmployee. It will contain the ID that we gave it but otherwise will have no other values because we haven’t hit the database yet.

Однако, как только мы вызываем методalbert:

String firstName = albert.getFirstName();

Затем Hibernate будет запрашивать таблицу базы данныхemployee для объекта с первичным ключом 1, заполняяalbert его свойствами из соответствующей строки.

Если не удается найти строку, Hibernate выдаетObjectNotFoundException.

3.2. Отношения один ко многим

Теперь давайте также создадим отправкуCompany , где aCompany has многоEmployees:

public class Company {
    private String name;
    private Set employees;
}

Если на этот раз использоватьSession.load() on the company:

Company bizco = session.load(Company.class, new Long(1));
String name = bizco.getName();

Затем свойства компании заполняются, как и раньше, за исключением того, что набор сотрудников немного отличается.

Видите ли, мы запросили только строку компании, но прокси оставит заданного сотрудника в покое, пока мы не вызовемgetEmployees в зависимости от стратегии выборки.

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();

bob will теперь будет инициализирован, и фактическиworkplace теперь будет настроен как неинициализированный прокси в зависимости от стратегии выборки.

4. Ленивая загрузка

Теперьload() won не всегда дает нам неинициализированный прокси. Фактически,Session java doc напоминает нам (выделено автором):

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

Простой пример того, когда это может произойти, с размером партии.

Допустим, мы используем@BatchSize в нашей отправкеEmployee :

@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 oncatherine:

String cathy = catherine.getFirstName();

Затем Hibernate может решить загрузить сразу всех трех сотрудников, превратив всех трех в инициализированные прокси.

А затем, когда мы вызываем имяdarrell:

String darrell = darrell.getFirstName();

ТогдаHibernate doesn’t hit the database at all.

5. Нетерпеливая загрузка

5.1. Используяget()

Мы также можем полностью обойти прокси и попросить Hibernate загрузить настоящую вещь, используяSession.get():

Employee finnigan = session.get(Employee.class, new Long(6));

Это вызовет базу данных сразу, а не вернет прокси.

И на самом деле вместоObjectNotFoundException он вернетnull, еслиfinnigan  не существует.

5.2. Последствия для производительности

Хотяget() удобен,load() может быть легче в базе данных.

Например, предположим, чтоgerald  будет работать в новой компании:

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() дляCompany  является разумным.

Если бы мы вызвалиget() наCompany, то мы без нужды загрузили бы все его данные из базы данных.

6. Заключение

В этой статье мы вкратце узнали, как работают проксиHibernate и как это влияет на методload с сущностями и их отношениями.

Также мы быстро посмотрели, чемload() отличается отget()..

Как обычно, доступен полный исходный код, прилагаемый к руководствуover on GitHub.