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
Аннотация @Cascade в Hibernate

Аннотация @Cascade (org.hibernate.annotations.Cascade) управляет каскадными операциями (сохранение, обновление, удаление) для ассоциаций между сущностями. Она дополняет или заменяет стандартные каскадные операции JPA (CascadeType).

Отличается от javax.persistence.CascadeType тем, что поддерживает специфичные для Hibernate каскады, например, CascadeType.LOCK или CascadeType.REPLICATE.

Параметры

Принимает одно или несколько значений из перечисления org.hibernate.annotations.CascadeType:
PERSIST – сохраняет связанную сущность при сохранении родителя (аналог CascadeType.PERSIST).
MERGE – обновляет связанную сущность при обновлении родителя (аналог CascadeType.MERGE).
REMOVE – удаляет связанную сущность при удалении родителя (аналог CascadeType.REMOVE).
REFRESH – обновляет связанную сущность при обновлении родителя (аналог CascadeType.REFRESH).
DETACH – отключает связанную сущность от контекста (аналог CascadeType.DETACH).
SAVE_UPDATE – сохраняет или обновляет связанную сущность при сохранении/обновлении родителя (устарело в Hibernate 6+, вместо этого используйте PERSIST + MERGE).
LOCK – блокирует связанную сущность при блокировке родителя (специфично для Hibernate).
REPLICATE – реплицирует связанную сущность при репликации родителя (специфично для Hibernate).
DELETE – удаляет связанную сущность при удалении родителя (аналог REMOVE, но работает в некоторых случаях иначе).
DELETE_ORPHAN – удаляет связанную сущность, если она больше не связана с родителем (работает только для коллекций).


Примеры использования

Каскадное сохранение и удаление
@Entity
public class Parent {
@Id
private Long id;

@OneToMany(mappedBy = "parent")
@Cascade({CascadeType.PERSIST, CascadeType.REMOVE})
private List<Child> children;
}


Что делает:
При сохранении Parent автоматически сохраняются все Child.
При удалении Parent автоматически удаляются все Child.


Каскадное обновление и управление "сиротами"
@Entity
public class Author {
@Id
private Long id;

@OneToMany(mappedBy = "author")
@Cascade({CascadeType.MERGE, CascadeType.DELETE_ORPHAN})
private List<Book> books;
}


Что делает:
При обновлении Author обновляются все связанные Book.
Если книга удаляется из списка books, она автоматически удаляется из БД (orphanRemoval).


Специфичные каскады Hibernate (LOCK, REPLICATE)
@Entity
public class Order {
@Id
private Long id;

@OneToMany(mappedBy = "order")
@Cascade({CascadeType.LOCK, CascadeType.REPLICATE})
private List<Item> items;
}


Что делает:
При блокировке Order блокируются все Item.
При репликации Order реплицируются все Item.


Разница между @Cascade и cascade в JPA

JPA (javax.persistence.CascadeType)
@OneToMany(mappedBy = "parent", cascade = {javax.persistence.CascadeType.PERSIST, javax.persistence.CascadeType.REMOVE})


Стандартный механизм JPA.
Поддерживает только базовые операции (PERSIST, MERGE, REMOVE, REFRESH, DETACH, ALL).


Hibernate (@Cascade)
@OneToMany(mappedBy = "parent")
@Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.DELETE_ORPHAN})


Расширенный функционал (например, DELETE_ORPHAN, LOCK, REPLICATE).
Работает только в Hibernate.


Когда использовать @Cascade?

Если нужны специфичные для Hibernate каскады (LOCK, REPLICATE).
Если требуется удаление "сирот" (DELETE_ORPHAN).
В остальных случаях лучше использовать стандартный cascade из JPA.


Оптимизация производительности

Каскадные операции могут приводить к неожиданным DELETE/UPDATE.

Рекомендуется:
Использовать orphanRemoval только там, где это необходимо.
Избегать CascadeType.ALL (может привести к неявным удалениям).


#Java #Training #Hard #Spring #Hibernate #Cascade
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
@ColumnTransformer в Hibernate / JPA

Аннотация @ColumnTransformer (из пакета org.hibernate.annotations) позволяет кастомизировать SQL-выражения для чтения (read) и записи (write) значений столбца в БД.

Используется, когда необходимо:
Применить функцию БД при загрузке (SELECT).
Преобразовать значение перед вставкой/обновлением (INSERT/UPDATE).
Работать с зашифрованными или вычисляемыми полями.


Аннотация принимает следующие атрибуты:

read (String):
SQL-выражение, применяемое при чтении значения из БД.
Может включать функции БД (например, decrypt, CAST, COALESCE).
Использует плейсхолдер ? для исходного значения столбца.


Пример:
@ColumnTransformer(read = "decrypt(credit_card_num, 'my_secret_key')")
private String creditCardNumber;


write (String):
SQL-выражение, применяемое при записи значения в БД.
Также использует плейсхолдер ? для нового значения.

Пример:
@ColumnTransformer(write = "encrypt(?, 'my_secret_key')")
private String password;


forColumn (String, опционально):
Указывает имя столбца, если оно отличается от имени поля в сущности.

Жизненный цикл и обработка

При загрузке сущности (SELECT)
Hibernate заменяет прямое обращение к столбцу на выражение из read.


Пример SQL:
SELECT decrypt(credit_card_num, 'my_secret_key') FROM users WHERE id = 1;


При сохранении (INSERT/UPDATE)
Значение поля преобразуется выражением из write.

Пример SQL:
INSERT INTO users (password) VALUES (encrypt('qwerty', 'my_secret_key'));


Нативные запросы
Если используется EntityManager.createNativeQuery(), @ColumnTransformer игнорируется (требуется ручное применение функций БД).

Механизмы Hibernate и интеграция

Генерация SQL
Обработка @ColumnTransformer происходит на этапе компиляции HQL в SQL (через ASTQueryTranslatorFactory).

Зависимость от диалекта БД
Выражения в read/write должны быть совместимы с диалектом БД (например, AES_ENCRYPT в MySQL, PGP_SYM_ENCRYPT в PostgreSQL).

Интеграция с JPA
Аннотация является Hibernate-специфичной и не входит в стандарт JPA.

Примеры использования

1. Шифрование данных
@Entity
public class User {
@Id
private Long id;

@ColumnTransformer(
read = "pgp_sym_decrypt(credit_card_num, 'secret_key')",
write = "pgp_sym_encrypt(?, 'secret_key')"
)
@Column(name = "credit_card_num")
private String creditCardNumber;
}


2. Преобразование типов
@ColumnTransformer(
read = "CAST(price AS decimal(10,2))",
write = "CAST(? AS varchar)"
)
private BigDecimal price;


3. Условные значения
@ColumnTransformer(
read = "COALESCE(status, 'DEFAULT')"
)
private String status;


Ограничения и настройки


Производительность

Сложные выражения могут замедлять запросы.

Поддержка в JPQL
В JPQL-запросах @ColumnTransformer не применяется (только в SQL, генерируемом Hibernate).

Альтернативы
Для сложной логики можно использовать:
@Convert (JPA 2.1).
Реализацию UserType в Hibernate.
Настройка через hibernate.xml
Нет глобальной настройки для
@ColumnTransformer — только через аннотации.

#Java #Training #Hard #Spring #Hibernate #ColumnTransformer
#Mems. Если вы вдруг забыли как делать версионизирование проекта
Что выведет код?

import java.util.function.Supplier;

public class Task080425 {
public static void main(String[] args) {
int x = 5;
Supplier<Integer> lambda = () -> x + 1;
x = 10;
System.out.println(lambda.get());
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
8%
5
59%
6
0%
123
32%
Ошибка компиляции
Не ну а чо, отгонять продукт-менеджеров же чем то надо 😏

https://t.me/Java_for_beginner_dev

#Mems
Please open Telegram to view this post
VIEW IN TELEGRAM
Вопросы с собеседования 👩‍💻

Какой метод используется для очистки ArrayList?
Anonymous Quiz
2%
empty()
4%
reset()
60%
clear()
33%
removeAll()
@DynamicInsert в Hibernate

Аннотация @DynamicInsert (из пакета org.hibernate.annotations) указывает Hibernate генерировать SQL-запросы INSERT только для ненулевых полей сущности. Это позволяет оптимизировать вставку данных, исключая из запроса столбцы со значениями null.

Применяется на уровне класса сущности:
@Entity
@DynamicInsert
public class User { ... }


У
@DynamicInsert нет настраиваемых атрибутов — это маркерная аннотация (присутствие/отсутствие влияет на поведение).

Как работает

Если @DynamicInsert = true (или аннотация присутствует):
Hibernate анализирует, какие поля сущности не null.
В SQL-запрос INSERT включаются только эти поля.


Если @DynamicInsert = false (по умолчанию):
В INSERT попадают все поля, включая null.

Примеры SQL

Без @DynamicInsert
User user = new User();
user.setId(1L);
user.setName("Alice"); // age = null


Сгенерированный SQL (все поля, даже age=null):
INSERT INTO user (id, name, age) VALUES (1, 'Alice', NULL);


С @DynamicInsert
@DynamicInsert
@Entity
public class User { ... }


Тот же код, но SQL будет короче:
INSERT INTO user (id, name) VALUES (1, 'Alice');  -- поле age пропущено!


Жизненный цикл и обработка

Во время компиляции маппинга
Hibernate определяет, нужно ли учитывать
@DynamicInsert для сущности.
При выполнении
session.save()
Проверяются значения полей.
Формируется SQL с учетом только ненулевых полей.
При генерации прокси-классов (если используется ленивая загрузка)
Не влияет напрямую, но может уменьшить объем данных в кеше.


Настройки и интеграция

В hibernate.cfg.xml или application.properties:
hibernate.dynamic_insert=true  # Применяется ко всем сущностям!


Но лучше использовать аннотацию для точечного контроля.

Совместимость с другими аннотациями

@DynamicUpdate – аналогично оптимизирует UPDATE.
@SelectBeforeUpdate – может конфликтовать (проверяет изменения перед UPDATE).


Когда использовать

Плюсы
Уменьшает размер SQL-запросов.
Ускоряет вставку, если много null-полей.
Полезно для таблиц с большим числом столбцов.


Минусы
Усложняет отладку (меняется SQL).
Незначительный оверхед на проверку null.
Бесполезен, если все поля обычно заполнены.


Оптимальные сценарии

Таблицы с 50+ столбцами, где большинство значений null.
Частые вставки частично заполненных объектов.
Работа с унаследованными системами, где NULL в столбцах нежелателен.


Примеры

Пример 1: Игнорирование null
@DynamicInsert
@Entity
public class Product {
@Id
private Long id;
private String name;
private Integer stock; // Часто null для новых товаров
}


При сохранении Product(id=1, name="Laptop", stock=null):
INSERT INTO product (id, name) VALUES (1, 'Laptop');


Комбинация с @ColumnDefault
@DynamicInsert
@Entity
public class Account {
@Id
private Long id;

@ColumnDefault("0")
private BigDecimal balance; // Если null, БД подставит 0
}


При Account(id=1, balance=null) в БД запишется balance=0.

Ограничения
Не работает с @GeneratedValue (Hibernate требует все поля для идентификации).
Не влияет на JPQL/HQL – только на SQL, генерируемый Hibernate.
Проблемы с кешированием – если кеш второго уровня ожидает полный объект.


#Java #Training #Hard #Spring #Hibernate #DynamicInsert
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
@DynamicUpdate в Hibernate

Аннотация @DynamicUpdate (из пакета org.hibernate.annotations) указывает Hibernate генерировать SQL-запросы UPDATE только для изменившихся полей сущности, а не для всех полей. Это улучшает производительность, особенно для таблиц с большим количеством столбцов.

Применяется на уровне класса сущности:
@Entity
@DynamicUpdate
public class User { ... }


Как работает


Если @DynamicUpdate = true (или аннотация присутствует):
Hibernate отслеживает изменения в полях сущности.
В SQL-запрос UPDATE включаются только измененные поля.


Если @DynamicUpdate = false (по умолчанию):
В UPDATE попадают все поля, даже если их значения не изменились.

Примеры SQL

Без @DynamicUpdate
User user = session.get(User.class, 1L);
user.setName("Alice"); // Меняем только имя


Сгенерированный SQL (все поля, даже неизмененные):
UPDATE user SET name='Alice', age=30, email='alice@example.com' WHERE id=1;


С @DynamicUpdate
@DynamicUpdate
@Entity
public class User { ... }


Тот же код, но SQL будет короче:
UPDATE user SET name='Alice' WHERE id=1;  -- Только измененное поле!


Жизненный цикл и обработка

При загрузке сущности
Hibernate сохраняет исходные значения полей (снимок состояния).

При изменении полей
Сравниваются текущие значения с исходными.

При выполнении session.update() или transaction.commit()
Формируется SQL только для измененных полей.

Влияние на кеширование
Кеш второго уровня обновляется только фактически измененными данными.

Настройки и интеграция

В hibernate.cfg.xml или application.properties:
hibernate.dynamic_update=true  # Применяется ко всем сущностям


Но рекомендуется использовать аннотацию для точного контроля.

Совместимость с другими аннотациями

@DynamicInsert – аналогичная оптимизация для INSERT.
@SelectBeforeUpdate – если true, Hibernate сначала загружает текущее состояние, что увеличивает точность @DynamicUpdate.

Когда использовать

Плюсы
Уменьшает объем SQL-запросов.
Ускоряет UPDATE для "широких" таблиц.
Снижает нагрузку на БД.


Минусы
Небольшой оверхед на отслеживание изменений.
Может усложнить отладку (меняется SQL).


Оптимальные сценарии

Таблицы с 20+ столбцами, где обновляются 1-2 поля.
Частые обновления части полей (например, счетчики, статусы).
Системы с высокой нагрузкой на БД.


#Java #Training #Hard #Spring #Hibernate #DynamicUpdate
Что выведет код?

import java.util.HashSet;
import java.util.Set;

public class Task090425 {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("A");
set.add(new String("A"));
set.add("B");
set.remove(new String("A"));

System.out.println(set.size());
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
43%
1
28%
2
20%
3
10%
Ошибка выполнения
Разочарование года 🤣

https://t.me/Java_for_beginner_dev

#Mems
Please open Telegram to view this post
VIEW IN TELEGRAM
Вопросы с собеседования 👩‍💻

Какой метод возвращает квадратный корень числа?
Anonymous Quiz
8%
Math.power()
14%
Math.square()
74%
Math.sqrt()
4%
Math.root()
@Filter в Hibernate

Аннотация @Filter позволяет динамически применять условия фильтрации к сущностям или коллекциям на уровне базы данных. Она используется для ограничения выборки данных в зависимости от заданных параметров. Находится в пакете org.hibernate.annotations.

Параметры и настройки

Аннотация @Filter имеет следующие атрибуты:

name (обязательный, String):
Уникальное имя фильтра, которое используется для его активации/деактивации в сессии.
Пример:
@Filter(name = "activeUserFilter").

condition (необязательный, String):
SQL-условие, которое добавляется в запрос при активации фильтра.
Может содержать параметры (например, :param), которые задаются во время выполнения.
Пример:
@Filter(name = "activeUserFilter", condition = "is_active = :activeStatus").

deduceAliasInjectionPoints (необязательный, boolean, default = true):
Определяет, должен ли Hibernate автоматически подставлять алиасы таблиц в условие.
Если false, условие должно содержать явные алиасы.


Жизненный цикл фильтра

Объявление фильтра:
Фильтр определяется на уровне класса сущности (@Entity) или коллекции (@ElementCollection, @OneToMany и др.).

Пример:
@Entity
@FilterDef(name = "activeUserFilter",
condition = "is_active = :activeStatus",
parameters = @ParamDef(name = "activeStatus", type = boolean.class))
@Filter(name = "activeUserFilter")
public class User { ... }


Активация фильтра в сессии:
Фильтр не активен по умолчанию, его нужно включать явно в Session или EntityManager.

Пример:
session.enableFilter("activeUserFilter")
.setParameter("activeStatus", true);


Применение в запросах:
После активации фильтр автоматически добавляет условие ко всем запросам, связанным с сущностью.
Для
@OneToMany и других коллекций фильтр применяется при загрузке ассоциаций.

Деактивация фильтра:
Фильтр можно отключить:
session.disableFilter("activeUserFilter");


Механизмы Hibernate и Spring, связанные с @Filter

1. @FilterDef и @ParamDef
@FilterDef определяет фильтр и его параметры.
@ParamDef задает тип параметра (например, String, boolean).
Должен быть указан на уровне класса (обычно на
@Entity или в package-info.java).

2. Интеграция с Spring Data JPA
Фильтры можно активировать в Spring-репозиториях через EntityManager:
@Repository
public class UserRepository {
@PersistenceContext
private EntityManager em;

public List<User> findActiveUsers() {
em.unwrap(Session.class)
.enableFilter("activeUserFilter")
.setParameter("activeStatus", true);
return em.createQuery("FROM User", User.class).getResultList();
}
}


3. Глобальная настройка фильтров в Spring Boot
Можно автоматически включать фильтры для всех запросов через @PostConstruct:
@Component
public class HibernateFilterConfig {
@PersistenceContext
private EntityManager em;

@PostConstruct
public void init() {
Session session = em.unwrap(Session.class);
session.enableFilter("activeUserFilter")
.setParameter("activeStatus", true);
}
}


Варианты настройки и применения

1. Фильтрация коллекций
@Entity
public class Department {
@OneToMany(mappedBy = "department")
@Filter(name = "activeUserFilter", condition = "is_active = :activeStatus")
private List<User> users;
}


2. Множественные фильтры
@Entity
@FilterDef(name = "activeFilter", condition = "is_active = :active")
@FilterDef(name = "roleFilter", condition = "role = :roleName")
@Filter(name = "activeFilter")
@Filter(name = "roleFilter")
public class User { ... }


3. Динамическое управление фильтрами
// Включение разных параметров в runtime
session.enableFilter("activeUserFilter")
.setParameter("activeStatus", true);
session.enableFilter("roleFilter")
.setParameter("roleName", "ADMIN");


#Java #Training #Hard #Spring #Hibernate #Filter #FilterDef
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM