Java for Beginner
672 subscribers
541 photos
155 videos
12 files
827 links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
@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:
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