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
Не ну а чо, отгонять продукт-менеджеров же чем то надо 😏

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
#Mems. Технологии, они не стоят на месте
@Formula в Hibernate

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

Атрибуты аннотации

value (String, обязательный):
SQL-выражение, которое выполняется при загрузке сущности из БД.
Может включать столбцы таблицы, агрегатные функции (SUM, AVG), подзапросы и даже вызовы SQL-функций.


Пример:
@Formula("(SELECT COUNT(*) FROM orders o WHERE o.customer_id = id)")
private int orderCount;


Жизненный цикл


Загрузка сущности:
При выборке сущности из БД (EntityManager.find(), HQL, Criteria API) Hibernate выполняет SQL из @Formula и подставляет результат в поле.
Вычисление происходит на стороне БД, а не в Java-коде.


Обновление сущности:
Поле, помеченное @Formula, не сохраняется в БД при INSERT/UPDATE.
Если SQL-выражение зависит от других полей, его значение пересчитывается при каждой загрузке.


Кэширование:
Если сущность кэшируется (например, через @Cacheable), значение @Formula также кэшируется.

Обработка @Formula

Во время компиляции Hibernate:
Hibernate парсит SQL-выражение и проверяет его синтаксис (но не валидирует до выполнения запроса).
Если выражение содержит ссылки на другие таблицы, Hibernate не создает JOIN автоматически – нужно явно указывать подзапросы.


В рантайме:
При генерации SQL для загрузки сущности Hibernate подставляет формулу как есть (без параметризации).

Зависимость от диалекта БД

Поскольку
@Formula использует "сырой" SQL, выражение должно быть совместимо с диалектом Hibernate (MySQLDialect, PostgreSQLDialect и т. д.).

Пример для PostgreSQL:
@Formula("CONCAT(first_name, ' ', last_name)")
private String fullName;
Для MySQL CONCAT работает аналогично, но в Oracle нужно использовать ||.


Варианты использования и ограничения

1. Динамические вычисления
Расчет рейтинга на основе связанных данных:
@Formula("(SELECT AVG(r.rating) FROM reviews r WHERE r.product_id = id)")
private Double averageRating;


2. Использование SQL-функций
Форматирование даты:
@Formula("TO_CHAR(created_at, 'YYYY-MM-DD')")
private String creationDate;


3. Ограничения
Нет поддержки JPA-стандарта: @Formula – это аннотация Hibernate, а не JPA.
Нет параметризации: SQL в
@Formula статичен, нельзя передавать параметры.
Производительность: Сложные подзапросы могут замедлять загрузку сущностей.


Альтернативы

@PostLoad + вычисление в Java:
@Transient
private int orderCount;

@PostLoad
private void calculateOrderCount() {
this.orderCount = orderRepository.countByCustomerId(this.id);
}


Плюс: независимость от SQL. Минус: вычисление в Java, а не в БД.
Представления (Database Views) + @Immutable:
Создать VIEW в БД и отобразить его как неизменяемую сущность.


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

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

class Person1004 {
String name;

Person1004(String name) { this.name = name; }

public boolean equals(Object o) {
return this.name.length() == ((Person1004)o).name.length();
}
}

public class Task100425 {
public static void main(String[] args) {
Set<Person1004> set = new HashSet<>();
set.add(new Person1004("Alice"));
set.add(new Person1004("Bob"));
set.add(new Person1004("Charlie"));
set.add(new Person1004("Dave"));

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


#Tasks
Варианты ответа:
Anonymous Quiz
3%
2
10%
3
80%
4
8%
Ошибка выполнения
🧐 А что бывает по другому?

https://t.me/Java_for_beginner_dev

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

Что такое default метод в интерфейсе?
Anonymous Quiz
13%
Метод без реализации
87%
Метод с реализацией по умолчанию
0%
Приватный метод
0%
Статический метод
@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
Please open Telegram to view this post
VIEW IN TELEGRAM