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
Основные аннотации JPA: @Entity, @Table, @Id

1. Аннотация @Entity
@Entity указывает, что класс представляет собой сущность базы данных. Каждая сущность соответствует таблице в базе данных.

Пример:
import jakarta.persistence.Entity;

@Entity
public class Product {
private Long id;
private String name;
private Double price;
}
Если класс помечен как @Entity, но таблица не указана явно, Spring автоматически использует название класса для создания таблицы в базе данных.


2. Аннотация @Table

@Table используется для настройки имени таблицы и схемы, к которой относится сущность.

Пример:
import jakarta.persistence.Entity;
import jakarta.persistence.Table;

@Entity
@Table(name = "products", schema = "shop")
public class Product {
private Long id;
private String name;
private Double price;
}
Если имя таблицы не указано, то по умолчанию используется имя класса.


3. Аннотация @Id

@Id используется для указания первичного ключа таблицы.

Пример:
import jakarta.persistence.Entity;
import jakarta.persistence.Id;

@Entity
public class Product {

@Id
private Long id;

private String name;
private Double price;
}


Другие полезные аннотации

1.
@GeneratedValue

Используется вместе с @Id для автоматической генерации значения первичного ключа.
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;


Стратегии генерации:
AUTO — автоматически выбирает стратегию, зависящую от базы данных.
IDENTITY — использует автоинкремент в базе данных.
SEQUENCE — использует специальную таблицу для генерации уникальных значений.
TABLE — сохраняет последовательности значений в отдельной таблице.


2. @Column

Позволяет указать имя столбца, его уникальность, длину и другие параметры.
import jakarta.persistence.Column;

@Column(name = "product_name", nullable = false, unique = true)
private String name;


3. @Transient

Позволяет исключить поле из отображения в базе данных.
@Transient
private String tempData;


Пример полной конфигурации
import jakarta.persistence.*;

@Entity
@Table(name = "products")
public class Product {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "product_name", nullable = false)
private String name;

private Double price;

@Transient
private String tempData;

// Getters and Setters
}


#Java #Training #Spring #Entity #Table #Id #GeneratedValue #Column #Transient
Аннотации @Cacheable и @CacheEvict

@Cacheable

Аннотация @Cacheable указывает, что результат метода должен быть сохранён в кеше. Если метод вызывается с теми же аргументами, то возвращается кешированное значение, а не выполняется метод.

Параметры

value / cacheNames (обязательный параметр)
Имя кеша, в который сохраняется результат. Можно указать одно или несколько значений.
```
@Cacheable("usersCache")
```
key (опциональный)
Позволяет задать ключ для кеша. Если не указано, ключ формируется автоматически на основе аргументов метода.
Можно использовать SpEL (Spring Expression Language) для создания ключей.
```
@Cacheable(value = "usersCache", key = "#id")
public User getUser(Long id) {
return userRepository.findById(id).orElse(null);
}
```

condition (опциональный)
Условие, при котором результат метода будет закеширован. Используется SpEL. Если условие не выполнено, кеширование не происходит.
@Cacheable(value = "usersCache", condition = "#id > 10")
public User getUser(Long id) {
return userRepository.findById(id).orElse(null);
}


unless (опциональный)
Условие, при котором результат НЕ будет кешироваться, даже если метод выполнен. Отличается от condition, так как проверяется после выполнения метода.
@Cacheable(value = "usersCache", unless = "#result == null")
public User getUser(Long id) {
return userRepository.findById(id).orElse(null);
}


sync (опциональный)
Если true, запросы для одного и того же ключа будут синхронизированы, чтобы предотвратить одновременное выполнение метода для одного ключа.
@Cacheable(value = "usersCache", sync = true)
public User getUser(Long id) {
return userRepository.findById(id).orElse(null);
}


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

1. Простое кеширование
Кеширование результата метода:
@Cacheable("usersCache")
public User getUser(Long id) {
System.out.println("Fetching user from database...");
return userRepository.findById(id).orElse(null);
}
Первый вызов с ID 1 сохранит результат в кеше.
Повторные вызовы с тем же ID вернут кешированные данные.


2. Сложный ключ для кеша
@Cacheable(value = "usersCache", key = "#user.id + '-' + #user.name")
public User getUserWithCustomKey(User user) {
return userRepository.findById(user.getId()).orElse(null);
}
Здесь ключом будет строка, содержащая ID и имя пользователя.


3. Использование условий
@Cacheable(value = "usersCache", condition = "#id > 1000")
public User getUser(Long id) {
return userRepository.findById(id).orElse(null);
}
Данные кешируются только для ID больше 1000.


#Java #Training #Spring #Cacheable
@CacheEvict

Аннотация @CacheEvict используется для удаления записей из кеша. Это необходимо, когда данные в кеше устарели, например, после обновления или удаления записи.

Параметры

value / cacheNames (обязательный параметр)
Указывает имя кеша, из которого нужно удалить записи.
@CacheEvict("usersCache")


key (опциональный)
Указывает ключ, который нужно удалить. Если не указано, удаляется запись, соответствующая ключу, сформированному из аргументов метода.
@CacheEvict(value = "usersCache", key = "#id")
public void deleteUser(Long id) {
userRepository.deleteById(id);
}


allEntries (опциональный)
Если true, очищает весь кеш. Используется для полного удаления всех записей в кеше.
@CacheEvict(value = "usersCache", allEntries = true)
public void clearCache() {
System.out.println("Cache cleared!");
}


beforeInvocation (опциональный)
Если true, удаление из кеша происходит до выполнения метода. По умолчанию удаление происходит после успешного выполнения метода.
@CacheEvict(value = "usersCache", key = "#id", beforeInvocation = true)
public void deleteUser(Long id) {
throw new RuntimeException("Error occurred!");
}


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

1. Удаление записи из кеша по ключу
@CacheEvict(value = "usersCache", key = "#id")
public void updateUser(Long id, User user) {
userRepository.save(user);
}
Обновляем пользователя и удаляем устаревшие данные из кеша.


2. Очистка всего кеша

@CacheEvict(value = "usersCache", allEntries = true)
public void clearAllUsersCache() {
System.out.println("All users cache cleared!");
}
Этот метод полностью очищает кеш usersCache.


3. Очистка перед выполнением метода

@CacheEvict(value = "usersCache", key = "#id", beforeInvocation = true)
public void deleteUser(Long id) {
// Логика удаления пользователя
userRepository.deleteById(id);
}
Кеш удаляется перед удалением пользователя из базы.


Совместное использование @Cacheable и @CacheEvict

Эти аннотации можно использовать вместе для полного управления кешем.

@Service
public class ProductService {

@Cacheable("productCache")
public Product getProduct(Long id) {
System.out.println("Fetching product from database...");
return productRepository.findById(id).orElse(null);
}

@CacheEvict(value = "productCache", key = "#id")
public void updateProduct(Long id, Product product) {
System.out.println("Updating product in database...");
productRepository.save(product);
}

@CacheEvict(value = "productCache", allEntries = true)
public void clearAllProductsCache() {
System.out.println("Clearing all product cache...");
}
}


Метод getProduct кеширует продукт.
Метод updateProduct удаляет устаревшие данные из кеша для обновлённого продукта.
Метод clearAllProductsCache очищает весь кеш продуктов.


Советы по использованию

Выбирайте правильный ключ: Убедитесь, что ключ уникален и логичен.
Учитывайте размер кеша: Не храните в кеше слишком большие данные.
Обновляйте кеш своевременно: Используйте
@CacheEvict для предотвращения устаревания данных.
Избегайте чрезмерного кеширования: Не кешируйте часто изменяющиеся данные.


#Java #Training #Spring #Cacheable #CacheEvict
Виды кеша в Spring и настройки конфигурации для Redis, Ehcache и Caffeine

Spring поддерживает разные провайдеры кеширования, что делает его универсальным инструментом. Настроим кеш для Redis, Ehcache и Caffeine.

1. Redis

Redis – это распределённый in-memory хранилище данных, которое поддерживает сложные структуры данных, TTL для кешей, и обеспечивает масштабируемость.


Нюансы работы с Redis

Хранение в памяти:
Все данные в Redis хранятся в оперативной памяти, что обеспечивает быструю скорость доступа.
Обязательно учитывайте объём данных и доступную оперативную память.


Поддержка TTL (время жизни):
Redis позволяет задавать время жизни для каждого ключа.
Это полезно для автоматического удаления устаревших данных.

@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
return RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10))) // Устанавливаем TTL 10 минут
.build();
}


Ключи кеша:
Redis кеширует данные по ключам, которые генерируются автоматически, если явно не указаны.
Рекомендуется явно задавать ключи с помощью параметра key в
@Cacheable.
@Cacheable(value = "productCache", key = "#id")
public Product getProductById(Long id) {
return productRepository.findById(id).orElse(null);
}


Проблемы с сериализацией:
Redis по умолчанию использует сериализацию JDK. Это может быть неэффективно.
Лучше использовать JSON-сериализацию, например, через Jackson.

@Bean
public RedisCacheConfiguration redisCacheConfiguration() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.findAndRegisterModules();

return RedisCacheConfiguration.defaultCacheConfig()
.serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(
new GenericJackson2JsonRedisSerializer(objectMapper)
)
);
}


Конкуренция за доступ к кешу:
Redis идеален для распределённых систем, но сетевые задержки могут влиять на производительность.
В локальных приложениях для небольших объёмов данных Redis использовать необязательно.


Шаги настройки Redis-кеша

Добавьте зависимости:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>io.lettuce.core</groupId>
<artifactId>lettuce-core</artifactId>
</dependency>


Настройте application.yml:

spring:
redis:
host: localhost
port: 6379
cache:
type: redis


Конфигурация Redis-кеша:
@Configuration
@EnableCaching
public class RedisCacheConfig {
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
return RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(RedisCacheConfiguration.defaultCacheConfig())
.build();
}
}
Теперь кеширование данных с помощью Redis работает.


#Java #Training #Spring #Redis
Примеры использования кеша на примере Caffeine и Redis

1. Пример с использованием Caffeine

Допустим, у нас есть метод, который возвращает данные пользователя.
@Service
public class UserService {

@Cacheable("usersCache")
public User getUserById(Long id) {
System.out.println("Fetching user from database...");
// Имитация запроса к базе данных
return new User(id, "User" + id);
}

@CacheEvict(value = "usersCache", key = "#id")
public void updateUser(Long id, User user) {
System.out.println("Updating user in database...");
// Обновление в базе
}
}


Проверка:
Первый вызов getUserById(1L) загрузит данные из базы.
Повторный вызов вернёт данные из кеша.
Метод updateUser(1L, user) очистит устаревшие данные из кеша.
Вывод: Кеш на базе Caffeine идеально подходит для небольших объёмов данных с высокой скоростью работы.


2. Пример с использованием Redis

Допустим, мы создаём приложение, где кеш хранится в Redis.
@Service
public class ProductService {

@Cacheable("productCache")
public Product getProductById(Long id) {
System.out.println("Fetching product from database...");
// Имитация запроса к базе данных
return new Product(id, "Product" + id);
}

@CacheEvict(value = "productCache", key = "#id")
public void updateProduct(Long id, Product product) {
System.out.println("Updating product in database...");
// Обновление в базе
}
}


Проверка:
При вызове getProductById(1L) данные сохраняются в Redis.
Повторный вызов с тем же
ID возвращает данные из Redis без обращения к базе.
Метод updateProduct(1L, product) удаляет кешированные данные.


Преимущества Redis:
Данные доступны для всех экземпляров приложения в распределённой системе.
Redis поддерживает TTL (время жизни кеша), что удобно для управления устареванием данных.


#Java #Training #Spring #Caffeine #Redis
Аннотация @Id

Аннотация @Id используется в Java Persistence API (JPA) для обозначения поля или свойства сущности, которое является первичным ключом (primary key) в базе данных. Она находится в пакете javax.persistence (или jakarta.persistence, если используется Jakarta EE). Эта аннотация является одной из ключевых в работе с JPA и ORM (Object-Relational Mapping).

Аннотация @Id не принимает никаких параметров. Она просто маркирует поле или геттер как первичный ключ сущности.

Настройки и значения

Поскольку @Id не имеет параметров, её настройка ограничивается выбором поля или свойства, которое будет использоваться в качестве первичного ключа.

Поле, помеченное @Id, должно соответствовать одному из следующих типов:
Примитивные типы: int, long, и т.д.
Обертки примитивных типов: Integer, Long, и т.д.
String
java.util.Date
java.sql.Date
java.math.BigDecimal
java.math.BigInteger
Если используется составной ключ (composite key), то вместо @
Id применяется @EmbeddedId или @IdClass.

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

Аннотация @Id применяется на этапе загрузки метаданных сущности (во время инициализации контекста Spring или при развертывании приложения).

Поле, помеченное @Id, используется JPA для:
Идентификации объекта в контексте persistence.
Сопоставления объекта с записью в базе данных.
Управления жизненным циклом сущности (например, при операциях persist, merge, remove).

Механизмы Spring и настройки Spring Boot

Механизмы Spring, связанные с @Id
Spring Data JPA использует аннотацию @Id для интеграции с JPA-провайдером (например, Hibernate).
При старте приложения Spring Boot автоматически сканирует сущности, помеченные аннотацией
@Entity, и анализирует их поля, включая те, что помечены @Id.
Spring Boot настраивает EntityManagerFactory и DataSource, которые используются JPA для работы с базой данных.


Настройки Spring Boot, предшествующие работе @Id

Конфигурация источника данных (DataSource):
Spring Boot автоматически настраивает DataSource на основе свойств, указанных в application.properties или application.yml.

Например:
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=secret
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
Эти настройки необходимы для подключения к базе данных, где хранятся сущности с первичными ключами.


Конфигурация JPA:
Spring Boot автоматически настраивает JPA через свойства, такие как:
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
Свойство spring.jpa.hibernate.ddl-auto управляет созданием и обновлением схемы базы данных, включая таблицы и первичные ключи.


Интеграция с Hibernate:
Hibernate, как JPA-провайдер, использует аннотацию @Id для создания SQL-запросов, таких как INSERT, UPDATE, SELECT, и DELETE, где первичный ключ играет ключевую роль.

Обработка значений @Id

При сохранении сущности (persist), JPA проверяет, что поле, помеченное @
Id, имеет уникальное значение.
Если поле @
Id имеет значение null, JPA интерпретирует это как новую сущность и генерирует для неё новый первичный ключ (если используется стратегия генерации ключей, например, @GeneratedValue).
При поиске сущности (find), JPA использует значение @
Id для выполнения запроса SELECT по первичному ключу.

Варианты настройки

Генерация значений первичного ключа:
Аннотация @Id часто используется вместе с @GeneratedValue, которая определяет стратегию генерации первичного ключа.

Составные ключи:
Если требуется составной ключ, вместо @Id используется @EmbeddedId или @IdClass.

#Java #Training #Hard #Spring #SpringDataJPA #Id