Рубрики
Без рубрики

Как включить усовершенствование байт-кода для проверки ошибок в режиме гибернации

Автор оригинала: Vlad Mihalcea.

Hibernate запускает механизм автоматической проверки на загрязнение во время промывки, и любое изменение состояния управляемой сущности преобразуется в инструкцию UPDATE SQL. Механизм проверки на загрязнение по умолчанию использует отражение Java и проходит через каждое свойство каждого управляемого объекта.

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

Hibernate предлагает поддержку инструментального байт-кода сущностей для трех вариантов использования:

  • ленивая инициализация (позволяет лениво извлекать атрибуты сущности)
  • грязное отслеживание (сущность отслеживает изменения своих собственных свойств)
  • управление ассоциациями (позволяет автоматически синхронизировать стороны для двунаправленных ассоциаций)

Несмотря на то, что он включал инструмент улучшения байт-кода начиная с версии 3.x, даже в режиме гибернации 4.x механизм улучшения байт-кода не был полностью реализован для проверки на наличие ошибок.

Среди многих других функций Hibernate 5.x поставляется с совершенно новой реализацией улучшения байт-кода, которая также устраняет механизм проверки на наличие ошибок. Хотя улучшение байт-кода может быть выполнено во время компиляции, во время выполнения или во время развертывания, альтернатива во время компиляции предпочтительна по следующим причинам:

  • расширенные классы могут быть охвачены модульными тестами
  • сервер приложений Java EE или автономный контейнер (например, Spring) могут загружаться быстрее, поскольку нет необходимости настраивать классы во время выполнения или во время развертывания
  • проблем с загрузкой классов можно избежать, так как серверу приложений не нужно заботиться о двух версиях одного и того же класса (исходной и расширенной).

Чтобы использовать все классы @Entity , вам необходимо добавить следующий плагин Maven:


    org.hibernate.orm.tooling
    hibernate-enhance-maven-plugin
    ${hibernate.version}
    
        
            
                true
            
            
                enhance
            
        
    

После компиляции классов Java плагин проходит через все классы сущностей и изменяет их байт-код в соответствии с параметрами инструментария, выбранными во время настройки.

При включении параметра отслеживание ошибок Hibernate будет отслеживать изменения свойств с помощью следующего механизма. Атрибут $$_hibernate_tracker хранит каждое изменение свойства, и каждый метод настройки вызовет $$_hibernate_trackChange метод.

@Transient
private transient DirtyTracker $$_hibernate_tracker;

public void $$_hibernate_trackChange(String paramString) {
    if (this.$$_hibernate_tracker == null) {
        this.$$_hibernate_tracker = new SimpleFieldTracker();
    }
    this.$$_hibernate_tracker.add(paramString);
}

Учитывая следующий оригинальный метод задания классов сущностей Java:

public void setTitle(String title) {
    this.title = title;
}

Hibernate преобразует его в следующее представление байт-кода:

public void setTitle(String title) {
    if(!EqualsHelper.areEqual(this.title, title)) {
        this.$$_hibernate_trackChange("title");
    }
    this.title = title;
}

Когда разработчик приложения вызывает метод setTitle с аргументом, отличным от сохраненного в данный момент заголовка , изменение будет записано в атрибуте класса $$_hibernate_tracker .

Во время очистки Hibernate проверяет метод $$_hibernate_hasDirtyAttributes , чтобы проверить, является ли объект загрязненным. Метод $$_hibernate_getDirtyAttributes выдает Строку [] , содержащую все грязные свойства.

public boolean $$_hibernate_hasDirtyAttributes() {
    return $$_hibernate_tracker != null && 
        !$$_hibernate_tracker.isEmpty();
}

public String[] $$_hibernate_getDirtyAttributes() {
    if($$_hibernate_tracker == null) {
        $$_hibernate_tracker = new SimpleFieldTracker();
    }
    return $$_hibernate_tracker.get();
}

Хотя отслеживание “грязного” байт-кода может ускорить механизм очистки контекста сохранения, если размер контекста сохранения довольно мал, улучшение не столь значительно.

Снимок сущности по-прежнему сохраняется в контексте сохранения даже при использовании улучшения байт-кода. По этой причине сохранение контекста сохранения в разумных границах сохраняется независимо от используемого механизма отслеживания ошибок.