«1. Обзор

Когда мы используем Spring Data JPA с Hibernate, мы также можем использовать дополнительные функции Hibernate. @DynamicUpdate — одна из таких функций.

@DynamicUpdate — это аннотация уровня класса, которую можно применить к объекту JPA. Это гарантирует, что Hibernate использует только измененные столбцы в операторе SQL, который он генерирует для обновления сущности.

В этой статье мы рассмотрим аннотацию @DynamicUpdate на примере Spring Data JPA.

2. JPA @Entity

Когда приложение запускается, Hibernate генерирует операторы SQL для операций CRUD всех объектов. Эти операторы SQL генерируются один раз и кэшируются в памяти для повышения производительности.

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

Давайте попробуем понять это на примере. Во-первых, давайте рассмотрим объект JPA с именем Account:

@Entity
public class Account {

    @Id
    private int id;

    @Column
    private String name;

    @Column
    private String type;

    @Column
    private boolean active;

    // Getters and Setters
}

Затем давайте напишем репозиторий JPA для объекта Account:

@Repository
public interface AccountRepository extends JpaRepository<Account, Integer> {
}

Теперь мы будем использовать AccountRepository для обновления поля имени Account. объект:

Account account = accountRepository.findOne(ACCOUNT_ID);
account.setName("Test Account");
accountRepository.save(account);

После выполнения этого обновления мы можем проверить сгенерированный оператор SQL. Сгенерированный оператор SQL будет включать все столбцы Account:

update Account set active=?, name=?, type=? where id=?

3. JPA @Entity с @DynamicUpdate

Мы видели, что, хотя мы изменили только поле имени, Hibernate включил все столбцы в операторе SQL.

Теперь добавим аннотацию @DynamicUpdate к объекту Account:

@Entity
@DynamicUpdate
public class Account {
    // Existing data and methods
}

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

update Account set name=? where id=?

Итак, что происходит, когда мы используем @DynamicUpdate для сущности?

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

Чтобы узнать измененные столбцы, Hibernate необходимо отслеживать состояние текущего объекта. Итак, когда мы изменяем какое-либо поле сущности, оно сравнивает текущее и измененное состояния сущности.

Это означает, что с @DynamicUpdate связаны накладные расходы на производительность. Поэтому мы должны использовать его только тогда, когда это действительно необходимо.

Конечно, есть несколько сценариев, в которых мы должны использовать эту аннотацию — например, если сущность представляет собой таблицу с большим количеством столбцов, и только некоторые из этих столбцов требуется часто обновлять. Кроме того, когда мы используем оптимистическую блокировку без версии, нам нужно использовать @DynamicUpdate.

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

В этом уроке мы рассмотрели аннотацию @DynamicUpdate для Hibernate. Мы использовали пример Spring Data JPA, чтобы увидеть @DynamicUpdate в действии. Кроме того, мы обсудили, когда нам следует использовать эту функцию, а когда нет.

Как всегда, полные примеры кода, используемые в этом руководстве, доступны на Github.