Java for Beginner
673 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
Вопросы с собеседования 👩‍💻

Какой метод используется для получения значения из Optional?
Anonymous Quiz
31%
value()
10%
fetch()
55%
get()
5%
retrieve()
@NaturalId в Hibernate

Аннотация @NaturalId помечает естественный (бизнес-идентификатор) поля сущности, который не является техническим первичным ключом (@Id), но обладает уникальностью и часто используется для поиска.

Пакет: org.hibernate.annotations
Применяется к: полям или свойствам сущности (String, Integer, UUID и др.).

Особенности:
Ускоряет поиск по "естественному" ключу (Hibernate кеширует NaturalId → ID).
Может быть изменяемым (mutable) или неизменяемым (immutable).


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

mutable: Если true — NaturalId можно изменить (по умолчанию false).

Примеры
@Entity
public class User {
@Id
private Long id;

@NaturalId(mutable = false) // Неизменяемый (оптимизирует кеширование)
private String email;

@NaturalId(mutable = true) // Изменяемый (редкий случай)
private String passportNumber;
}


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

Как работает
@NaturalId?

При сохранении:
Hibernate проверяет уникальность NaturalId (если нет @UniqueConstraint).
Добавляет запись в кеш NaturalId → ID.


При поиске:
session.bySimpleNaturalId(User.class).load("test@mail.com") — использует кеш.
Генерирует SQL: SELECT id FROM users WHERE email = ?.


При изменении (если mutable=true):
Обновляет кеш (старое значение удаляется, новое добавляется).

Кеширование
Уровень L1 (сессия): Кешируется в рамках текущей сессии.

Уровень L2 (глобальный): Требует включенного кеша второго уровня.

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

Пример 1: Неизменяемый NaturalId
@Entity
@Table(uniqueConstraints = @UniqueConstraint(columnNames = "isbn"))
public class Book {
@Id
private Long id;

@NaturalId // immutable=false по умолчанию
private String isbn;
}


Пример 2: Поиск по NaturalId
Book book = session.bySimpleNaturalId(Book.class)
.load("978-3-16-148410-0");


Ограничения

Производительность при mutable=true:
Частые изменения NaturalId требуют обновления кеша.

Отсутствие JPA-стандарта:
@NaturalId — это фича Hibernate (не работает в EclipseLink).

Когда использовать?
Для часто используемых бизнес-идентификаторов (email, ISBN, серийные номера).
Вместо @Id, если первичный ключ — суррогатный (автоинкремент).


#Java #Training #Hard #Spring #Hibernate #NaturalId
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Завтра все может быть иначе!

#Mems
@NotFound в Hibernate

Аннотация @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
Что выведет код?

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
Варианты ответа:
Anonymous Quiz
12%
1
56%
2
28%
3
4%
256
Микросервисная архитектура на примере 😎

https://t.me/Java_for_beginner_dev

#Mems
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 (обнулить ссылку).

Примеры
@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
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
@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-запроса
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
Что выведет код?

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
Варианты ответа:
Anonymous Quiz
17%
0
44%
1
25%
99
14%
100
Please open Telegram to view this post
VIEW IN TELEGRAM
@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).


Примеры
@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