@NotFound в Hibernate
Аннотация @NotFound управляет поведением Hibernate при отсутствии ссылки на связанную сущность в базе данных (например, если @ManyToOne ссылается на несуществующий ID).
Пакет: org.hibernate.annotations
Применяется к: ассоциациям (@OneToOne, @ManyToOne, @OneToMany, @ManyToMany).
Поведение по умолчанию: Hibernate выбрасывает EntityNotFoundException.
Параметры и настройки
action: Действие при отсутствии сущности: EXCEPTION (по умолчанию) или IGNORE.
Примеры
Жизненный цикл и обработка
Как работает @NotFound?
При загрузке сущности:
Если связанная сущность (например, User) не найдена:
action = EXCEPTION → EntityNotFoundException.
action = IGNORE → поле устанавливается в null.
При каскадных операциях:
Не влияет на CascadeType (удаление, обновление).
Сценарии
Ссылка на удаленную сущность:
Ленивая загрузка:
Если прокси не может загрузить сущность, применяется action.
Интеграция с Spring Boot
Валидация при старте:
Чтобы выявить "битые" ссылки заранее:
Логирование:
Примеры использования
Пример 1: Игнорирование отсутствующей сущности
Пример 2: Обработка в сервисе
Проблемы
Неявное поведение:
IGNORE может скрывать ошибки данных.
Нет поддержки в JPA:
Это фича Hibernate (не работает в EclipseLink).
Когда использовать?
Для опциональных ассоциаций, где null — допустимое состояние.
В legacy-системах с "битыми" ссылками.
#Java #Training #Hard #Spring #Hibernate #NotFound
Аннотация @NotFound управляет поведением Hibernate при отсутствии ссылки на связанную сущность в базе данных (например, если @ManyToOne ссылается на несуществующий ID).
Пакет: org.hibernate.annotations
Применяется к: ассоциациям (@OneToOne, @ManyToOne, @OneToMany, @ManyToMany).
Поведение по умолчанию: Hibernate выбрасывает EntityNotFoundException.
Параметры и настройки
action: Действие при отсутствии сущности: EXCEPTION (по умолчанию) или IGNORE.
Примеры
@Entity
public class Order {
@ManyToOne
@NotFound(action = NotFoundAction.IGNORE) // Игнорировать отсутствие пользователя
private User user;
}
Жизненный цикл и обработка
Как работает @NotFound?
При загрузке сущности:
Если связанная сущность (например, User) не найдена:
action = EXCEPTION → EntityNotFoundException.
action = IGNORE → поле устанавливается в null.
При каскадных операциях:
Не влияет на CascadeType (удаление, обновление).
Сценарии
Ссылка на удаленную сущность:
-- order.user_id = 999, но users.id = 999 не существует
@NotFound(action = IGNORE) → order.user = null.
Ленивая загрузка:
Если прокси не может загрузить сущность, применяется action.
Интеграция с Spring Boot
Валидация при старте:
Чтобы выявить "битые" ссылки заранее:
@EventListener(ApplicationReadyEvent.class)
public void checkBrokenReferences() {
// Ручная проверка...
}
Логирование:
logging.level.org.hibernate=DEBUG
Примеры использования
Пример 1: Игнорирование отсутствующей сущности
@Entity
public class Comment {
@ManyToOne
@NotFound(action = NotFoundAction.IGNORE)
private Post post; // Если post удалён, comment.post = null
}
Пример 2: Обработка в сервисе
public CommentDTO getComment(Long id) {
Comment comment = commentRepository.findById(id).orElseThrow();
if (comment.getPost() == null) {
log.warn("Пост для комментария {} не найден", id);
}
return toDto(comment);
}
Проблемы
Неявное поведение:
IGNORE может скрывать ошибки данных.
Нет поддержки в JPA:
Это фича Hibernate (не работает в EclipseLink).
Когда использовать?
Для опциональных ассоциаций, где null — допустимое состояние.
В legacy-системах с "битыми" ссылками.
#Java #Training #Hard #Spring #Hibernate #NotFound
Что выведет код?
#Tasks
import java.util.HashMap;
class Key170425 {
int id;
Key170425(int id) {
this.id = id;
}
@Override
public int hashCode() {
return id % 2;
}
@Override
public boolean equals(Object o) {
return this.id % 2 == ((Key170425)o).id % 2;
}
}
public class Task170425 {
public static void main(String[] args) {
HashMap<Key170425, String> map = new HashMap<>();
map.put(new Key170425(1), "Apple");
map.put(new Key170425(2), "Banana");
map.put(new Key170425(3), "Cherry");
System.out.println(map.size());
}
}
#Tasks
Please open Telegram to view this post
VIEW IN TELEGRAM
Вопросы с собеседования 👩💻
Какой метод используется для округления числа вниз?
Какой метод используется для округления числа вниз?
Anonymous Quiz
56%
Math.floor()
20%
Math.ceil()
22%
Math.round()
2%
Math.trunc()
@OnDelete в Hibernate
Аннотация @OnDelete определяет действие при удалении связанной сущности на уровне базы данных (через ON DELETE CASCADE или ON DELETE SET NULL). Это DDL-инструкция, а не логика Hibernate.
Пакет: org.hibernate.annotations
Применяется к: ассоциациям (@OneToOne, @ManyToOne, @OneToMany).
Влияние: Генерирует соответствующий SQL-констрейнт в БД.
Параметры и настройки
action: Варианты: CASCADE (удалить зависимые записи) или SET_NULL (обнулить ссылку).
Примеры
Жизненный цикл и обработка
Как работает @OnDelete?
При генерации DDL:
Hibernate добавляет в SQL-скрипт ON DELETE CASCADE/SET NULL для внешнего ключа.
При удалении через БД:
Если запись удаляется напрямую SQL (минуя Hibernate), констрейнт срабатывает автоматически.
При удалении через Hibernate:
Если action = CASCADE, Hibernate сначала удаляет дочерние сущности (если нет orphanRemoval).
Ограничения
Не влияет на логику EntityManager.remove().
Не работает с @ManyToMany (только через @JoinTable + отдельные констрейнты).
Примеры использования
Пример 1: Каскадное удаление (CASCADE)
Пример 2: Обнуление ссылки (SET_NULL)
Проблемы
Неявное удаление: При CASCADE данные могут исчезнуть без явного вызова delete().
Несовместимость: Некоторые БД (например, MySQL с InnoDB) требуют индексов для ON DELETE CASCADE.
Когда использовать?
Для жестких зависимостей (например, Order → User).
В legacy-системах, где удаление управляется триггерами БД.
#Java #Training #Hard #Spring #Hibernate #OnDelete
Аннотация @OnDelete определяет действие при удалении связанной сущности на уровне базы данных (через ON DELETE CASCADE или ON DELETE SET NULL). Это DDL-инструкция, а не логика Hibernate.
Пакет: org.hibernate.annotations
Применяется к: ассоциациям (@OneToOne, @ManyToOne, @OneToMany).
Влияние: Генерирует соответствующий SQL-констрейнт в БД.
Параметры и настройки
action: Варианты: CASCADE (удалить зависимые записи) или SET_NULL (обнулить ссылку).
Примеры
@Entity
public class Order {
@ManyToOne
@OnDelete(action = OnDeleteAction.CASCADE) // При удалении User удалятся его Order
private User user;
}
Жизненный цикл и обработка
Как работает @OnDelete?
При генерации DDL:
Hibernate добавляет в SQL-скрипт ON DELETE CASCADE/SET NULL для внешнего ключа.
При удалении через БД:
Если запись удаляется напрямую SQL (минуя Hibernate), констрейнт срабатывает автоматически.
При удалении через Hibernate:
Если action = CASCADE, Hibernate сначала удаляет дочерние сущности (если нет orphanRemoval).
Ограничения
Не влияет на логику EntityManager.remove().
Не работает с @ManyToMany (только через @JoinTable + отдельные констрейнты).
Примеры использования
Пример 1: Каскадное удаление (CASCADE)
@Entity
public class Comment {
@ManyToOne
@OnDelete(action = OnDeleteAction.CASCADE) // Удалить комментарии при удалении Post
private Post post;
}
Пример 2: Обнуление ссылки (SET_NULL)
@Entity
public class Employee {
@ManyToOne
@OnDelete(action = OnDeleteAction.SET_NULL) // department_id = NULL при удалении Department
private Department department;
}
Проблемы
Неявное удаление: При CASCADE данные могут исчезнуть без явного вызова delete().
Несовместимость: Некоторые БД (например, MySQL с InnoDB) требуют индексов для ON DELETE CASCADE.
Когда использовать?
Для жестких зависимостей (например, Order → User).
В legacy-системах, где удаление управляется триггерами БД.
#Java #Training #Hard #Spring #Hibernate #OnDelete
@TableGenerator в JPA
Аннотация @TableGenerator позволяет настраивать генерацию уникальных идентификаторов для сущностей с использованием высокоуровневого механизма, основанного на выделении диапазонов значений.
Пакет: javax.persistence (JPA)
Применяется к: полю с @Id и @GeneratedValue(strategy = GenerationType.TABLE).
Параметры и настройки
Основные атрибуты
name: Уникальное имя генератора (обязательно).
table: Специальный объект для хранения значений (по умолчанию hibernate_sequences).
pkColumnName: Столбец, хранящий имена генераторов (по умолчанию sequence_name).
valueColumnName: Столбец, хранящий текущее значение (по умолчанию next_val).
pkColumnValue: Имя текущего генератора в pkColumnName (по умолчанию имя сущности).
initialValue: Начальное значение (по умолчанию 0).
allocationSize: Размер выделяемого блока значений (по умолчанию 50).
catalog: Каталог в БД (опционально).
schema: Схема в БД (опционально).
uniqueConstraints: Ограничения уникальности (опционально).
Жизненный цикл и обработка
Как работает генерация ID?
При старте приложения:
Если специльный объект не существует, Hibernate создает его автоматически (если ddl-auto=create или update).
При сохранении новой сущности:
Hibernate запрашивает новый диапазон значений (размером allocationSize).
Значения выделяются пакетно, что уменьшает количество обращений к БД.
При исчерпании диапазона:
Hibernate автоматически запрашивает следующий блок.
Пример SQL-запроса
Интеграция с Spring Boot
Автогенерация схемы:
Кастомизация имени объекта:
Примеры использования
Пример 1: Базовая настройка
Пример 2: Кастомизация схемы
Проблемы
Производительность: Частые запросы к БД при малом allocationSize.
Блокировки: Использует SELECT ... FOR UPDATE, что может вызвать конкуренцию.
Когда использовать?
Когда не поддерживаются SEQUENCE (например, MySQL до 8.0).
Для переносимости между разными СУБД.
#Java #Training #Hard #Spring #JPA #TableGenerator
Аннотация @TableGenerator позволяет настраивать генерацию уникальных идентификаторов для сущностей с использованием высокоуровневого механизма, основанного на выделении диапазонов значений.
Пакет: javax.persistence (JPA)
Применяется к: полю с @Id и @GeneratedValue(strategy = GenerationType.TABLE).
Параметры и настройки
Основные атрибуты
name: Уникальное имя генератора (обязательно).
table: Специальный объект для хранения значений (по умолчанию hibernate_sequences).
pkColumnName: Столбец, хранящий имена генераторов (по умолчанию sequence_name).
valueColumnName: Столбец, хранящий текущее значение (по умолчанию next_val).
pkColumnValue: Имя текущего генератора в pkColumnName (по умолчанию имя сущности).
initialValue: Начальное значение (по умолчанию 0).
allocationSize: Размер выделяемого блока значений (по умолчанию 50).
catalog: Каталог в БД (опционально).
schema: Схема в БД (опционально).
uniqueConstraints: Ограничения уникальности (опционально).
Жизненный цикл и обработка
Как работает генерация ID?
При старте приложения:
Если специльный объект не существует, Hibernate создает его автоматически (если ddl-auto=create или update).
При сохранении новой сущности:
Hibernate запрашивает новый диапазон значений (размером allocationSize).
Значения выделяются пакетно, что уменьшает количество обращений к БД.
При исчерпании диапазона:
Hibernate автоматически запрашивает следующий блок.
Пример SQL-запроса
SELECT next_val FROM hibernate_sequences WHERE sequence_name = 'employee_seq' FOR UPDATE;
UPDATE hibernate_sequences SET next_val = next_val + 50 WHERE sequence_name = 'employee_seq';
Интеграция с Spring Boot
Автогенерация схемы:
spring.jpa.hibernate.ddl-auto=update
Кастомизация имени объекта:
@TableGenerator(
name = "book_seq",
table = "custom_sequences",
pkColumnName = "seq_name",
valueColumnName = "seq_value",
allocationSize = 30
)
Примеры использования
Пример 1: Базовая настройка
@Entity
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "emp_seq")
@TableGenerator(
name = "emp_seq",
allocationSize = 20
)
private Long id;
}
Пример 2: Кастомизация схемы
@TableGenerator(
name = "project_seq",
schema = "hr",
table = "project_sequences",
initialValue = 1000
)
Проблемы
Производительность: Частые запросы к БД при малом allocationSize.
Блокировки: Использует SELECT ... FOR UPDATE, что может вызвать конкуренцию.
Когда использовать?
Когда не поддерживаются SEQUENCE (например, MySQL до 8.0).
Для переносимости между разными СУБД.
#Java #Training #Hard #Spring #JPA #TableGenerator
Что выведет код?
#Tasks
import java.util.HashSet;
public class Task180425 {
public static void main(String[] args) {
HashSet<Short> set = new HashSet<>();
for (short i = 0; i < 100; i++) {
set.add(i);
set.remove(i - 1);
}
System.out.println(set.size());
}
}
#Tasks
Please open Telegram to view this post
VIEW IN TELEGRAM
Вопросы с собеседования 👩💻
Что такое Comparable?
Что такое Comparable?
Anonymous Quiz
2%
Класс для работы с числами
7%
Метод для сортировки
89%
Интерфейс для сравнения объектов
2%
Аннотация для методов
@OptimisticLock в Hibernate
Аннотация @OptimisticLock управляет оптимистичной блокировкой сущности в Hibernate, определяя, какие поля должны проверяться на изменение при обновлении.
Пакет: org.hibernate.annotations
Применяется к: классу сущности (@Entity) или отдельным полям.
Стратегии:
OptimisticLockType.VERSION (по умолчанию) — использует @Version.
OptimisticLockType.ALL — проверяет все поля.
OptimisticLockType.DIRTY — проверяет только измененные поля.
OptimisticLockType.NONE — отключает проверку.
Параметры и настройки
Атрибуты
type: Стратегия проверки изменений (VERSION, ALL, DIRTY, NONE).
excluded: Если true, поле исключается из проверки (при type = ALL/DIRTY).
Примеры
Жизненный цикл и обработка
Как работает оптимистичная блокировка?
При чтении сущности:
Hibernate запоминает состояние полей (для ALL/DIRTY).
При обновлении:
Генерируется SQL вида:
Если условие не выполняется (данные изменились), выбрасывается OptimisticLockException.
Интеграция с Spring Boot
Глобальная стратегия:
Обработка исключений:
Примеры использования
Пример 1: Проверка всех полей
Пример 2: Исключение поля
Проблемы
ALL/DIRTY: Требуют хранения исходного состояния (память).
Нет поддержки в JPA: Только Hibernate.
Когда использовать?
VERSION — для большинства случаев.
DIRTY — для больших сущностей с редкими конфликтами.
#Java #Training #Hard #Spring #Hibernate #OptimisticLock
Аннотация @OptimisticLock управляет оптимистичной блокировкой сущности в Hibernate, определяя, какие поля должны проверяться на изменение при обновлении.
Пакет: org.hibernate.annotations
Применяется к: классу сущности (@Entity) или отдельным полям.
Стратегии:
OptimisticLockType.VERSION (по умолчанию) — использует @Version.
OptimisticLockType.ALL — проверяет все поля.
OptimisticLockType.DIRTY — проверяет только измененные поля.
OptimisticLockType.NONE — отключает проверку.
Параметры и настройки
Атрибуты
type: Стратегия проверки изменений (VERSION, ALL, DIRTY, NONE).
excluded: Если true, поле исключается из проверки (при type = ALL/DIRTY).
Примеры
@Entity
@OptimisticLock(type = OptimisticLockType.ALL)
public class Account {
@Id
private Long id;
@OptimisticLock(excluded = true) // Не проверяется при обновлении
private String secretCode;
}
Жизненный цикл и обработка
Как работает оптимистичная блокировка?
При чтении сущности:
Hibernate запоминает состояние полей (для ALL/DIRTY).
При обновлении:
Генерируется SQL вида:
UPDATE account SET ... WHERE id = ? AND (secretCode IS NULL OR secretCode = ?)
Если условие не выполняется (данные изменились), выбрасывается OptimisticLockException.
Интеграция с Spring Boot
Глобальная стратегия:
spring.jpa.properties.hibernate.optimistic_lock.strategy=all
Обработка исключений:
@ExceptionHandler(OptimisticLockException.class)
public void handleConflict() { /* ... */ }
Примеры использования
Пример 1: Проверка всех полей
@Entity
@OptimisticLock(type = OptimisticLockType.ALL)
public class Product {
@Version
private Long version; // Дополнительная проверка
}
Пример 2: Исключение поля
@Entity
@OptimisticLock(type = OptimisticLockType.DIRTY)
public class User {
@OptimisticLock(excluded = true)
private LocalDateTime lastLogin;
}
Проблемы
ALL/DIRTY: Требуют хранения исходного состояния (память).
Нет поддержки в JPA: Только Hibernate.
Когда использовать?
VERSION — для большинства случаев.
DIRTY — для больших сущностей с редкими конфликтами.
#Java #Training #Hard #Spring #Hibernate #OptimisticLock
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM