@Generated в Hibernate
Аннотация @Generated указывает, что значение поля автоматически генерируется базой данных (например, через DEFAULT, TRIGGER, AUTO_INCREMENT или вычисляемый столбец). В отличие от @Formula, поле сохраняется в БД, но Hibernate обновляет его после вставки или обновления. Находится в пакете org.hibernate.annotations.
Атрибуты аннотации
GenerationTime (обязательный):
Определяет, когда значение генерируется:
GenerationTime.INSERT – только при вставке (например, AUTO_INCREMENT).
GenerationTime.ALWAYS – при вставке и обновлении (например, триггеры или DEFAULT-значения).
value (необязательный, String):
SQL-выражение, которое генерирует значение (если БД поддерживает, например, DEFAULT CURRENT_TIMESTAMP).
Используется редко, так как обычно генерация определяется на стороне БД.
Жизненный цикл
При сохранении (INSERT)
Если GenerationTime.INSERT или GenerationTime.ALWAYS:
Hibernate выполняет INSERT, пропуская это поле.
После вставки делает SELECT (или использует RETURNING в PostgreSQL), чтобы получить сгенерированное значение.
Пример для AUTO_INCREMENT:
При обновлении (UPDATE)
Если GenerationTime.ALWAYS:
Hibernate пропускает поле в UPDATE.
После обновления делает SELECT для получения нового значения.
Пример для триггера, обновляющего last_modified:
Кэширование
Если включен кэш второго уровня (@Cacheable), Hibernate обновляет значение в кэше после SELECT.
Механизмы Hibernate и настройки
1. Как Hibernate обрабатывает @Generated
Генерация SQL:
Поле исключается из INSERT/UPDATE.
Для получения значения выполняется дополнительный SELECT (если БД не поддерживает RETURNING).
Поддержка RETURNING (PostgreSQL, Oracle, SQL Server):
Если диалект поддерживает RETURNING, Hibernate использует его вместо отдельного SELECT:
2. Зависимость от диалекта БД
Поведение зависит от возможностей БД:
MySQL: AUTO_INCREMENT, DEFAULT CURRENT_TIMESTAMP.
PostgreSQL: SERIAL, GENERATED ALWAYS AS IDENTITY, триггеры.
Oracle: SEQUENCE + триггеры, DEFAULT-значения.
Примеры использования
1. Автоинкрементный ID
Эквивалент Hibernate:
2. Временная метка создания
3. Триггер для аудита
Ограничения и альтернативы
Ограничения:
Не все БД поддерживают RETURNING:
Для MySQL требуется дополнительный SELECT.
Нет контроля над генерацией:
Логика полностью определяется БД (триггеры, DEFAULT).
Альтернативы:
@PrePersist и @PreUpdate (JPA):
#Java #Training #Hard #Spring #Hibernate #Generated
Аннотация @Generated указывает, что значение поля автоматически генерируется базой данных (например, через DEFAULT, TRIGGER, AUTO_INCREMENT или вычисляемый столбец). В отличие от @Formula, поле сохраняется в БД, но Hibernate обновляет его после вставки или обновления. Находится в пакете org.hibernate.annotations.
Атрибуты аннотации
GenerationTime (обязательный):
Определяет, когда значение генерируется:
GenerationTime.INSERT – только при вставке (например, AUTO_INCREMENT).
GenerationTime.ALWAYS – при вставке и обновлении (например, триггеры или DEFAULT-значения).
value (необязательный, String):
SQL-выражение, которое генерирует значение (если БД поддерживает, например, DEFAULT CURRENT_TIMESTAMP).
Используется редко, так как обычно генерация определяется на стороне БД.
Жизненный цикл
При сохранении (INSERT)
Если GenerationTime.INSERT или GenerationTime.ALWAYS:
Hibernate выполняет INSERT, пропуская это поле.
После вставки делает SELECT (или использует RETURNING в PostgreSQL), чтобы получить сгенерированное значение.
Пример для AUTO_INCREMENT:
INSERT INTO users (name) VALUES ('Alice'); -- id не указывается
SELECT last_insert_id(); -- Hibernate получает сгенерированный ID
При обновлении (UPDATE)
Если GenerationTime.ALWAYS:
Hibernate пропускает поле в UPDATE.
После обновления делает SELECT для получения нового значения.
Пример для триггера, обновляющего last_modified:
UPDATE users SET name = 'Bob' WHERE id = 1; -- last_modified не указывается
SELECT last_modified FROM users WHERE id = 1; -- Hibernate получает новое значение
Кэширование
Если включен кэш второго уровня (@Cacheable), Hibernate обновляет значение в кэше после SELECT.
Механизмы Hibernate и настройки
1. Как Hibernate обрабатывает @Generated
Генерация SQL:
Поле исключается из INSERT/UPDATE.
Для получения значения выполняется дополнительный SELECT (если БД не поддерживает RETURNING).
Поддержка RETURNING (PostgreSQL, Oracle, SQL Server):
Если диалект поддерживает RETURNING, Hibernate использует его вместо отдельного SELECT:
INSERT INTO users (name) VALUES ('Alice') RETURNING id, created_at;
2. Зависимость от диалекта БД
Поведение зависит от возможностей БД:
MySQL: AUTO_INCREMENT, DEFAULT CURRENT_TIMESTAMP.
PostgreSQL: SERIAL, GENERATED ALWAYS AS IDENTITY, триггеры.
Oracle: SEQUENCE + триггеры, DEFAULT-значения.
Примеры использования
1. Автоинкрементный ID
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // Аналог для JPA
private Long id;
Эквивалент Hibernate:
@Id
@Generated(GenerationTime.INSERT)
private Long id;
2. Временная метка создания
@Column(insertable = false) // Не указывается в INSERT
@Generated(GenerationTime.INSERT)
private LocalDateTime createdAt; // DEFAULT CURRENT_TIMESTAMP в БД
3. Триггер для аудита
@Column(updatable = false)
@Generated(GenerationTime.ALWAYS)
private LocalDateTime lastModified; // Обновляется триггером БД
Ограничения и альтернативы
Ограничения:
Не все БД поддерживают RETURNING:
Для MySQL требуется дополнительный SELECT.
Нет контроля над генерацией:
Логика полностью определяется БД (триггеры, DEFAULT).
Альтернативы:
@PrePersist и @PreUpdate (JPA):
@PrePersist
private void prePersist() {
this.createdAt = LocalDateTime.now();
}
Плюс: работает везде. Минус: значение генерируется в Java, а не в БД.
#Java #Training #Hard #Spring #Hibernate #Generated