"А еще у них код грязный, потому что не моются месяцами" 🤪😂😂😂
https://t.me/Java_for_beginner_dev
#Mems
https://t.me/Java_for_beginner_dev
#Mems
Основные аннотации JPA: @Entity, @Table, @Id
1. Аннотация @Entity
@Entity указывает, что класс представляет собой сущность базы данных. Каждая сущность соответствует таблице в базе данных.
Пример:
2. Аннотация @Table
@Table используется для настройки имени таблицы и схемы, к которой относится сущность.
Пример:
3. Аннотация @Id
@Id используется для указания первичного ключа таблицы.
Пример:
Другие полезные аннотации
1. @GeneratedValue
Используется вместе с @Id для автоматической генерации значения первичного ключа.
Стратегии генерации:
AUTO — автоматически выбирает стратегию, зависящую от базы данных.
IDENTITY — использует автоинкремент в базе данных.
SEQUENCE — использует специальную таблицу для генерации уникальных значений.
TABLE — сохраняет последовательности значений в отдельной таблице.
2. @Column
Позволяет указать имя столбца, его уникальность, длину и другие параметры.
3. @Transient
Позволяет исключить поле из отображения в базе данных.
Пример полной конфигурации
#Java #Training #Spring #Entity #Table #Id #GeneratedValue #Column #Transient
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
Аннотации JPA для полей: @Column, @GeneratedValue, @ManyToOne
1. Аннотация @Column
Аннотация @Column используется для настройки маппинга поля сущности на столбец таблицы базы данных. С её помощью можно задать имя столбца, его длину, уникальность, возможность быть NULL и другие атрибуты.
Основные параметры:
name — имя столбца в базе данных.
nullable — допускает ли столбец значение NULL.
unique — устанавливает, должны ли значения в столбце быть уникальными.
length — длина для столбцов типа VARCHAR.
columnDefinition — SQL-выражение для явного указания типа столбца.
Пример использования:
В этом примере мы видим, что:
Поле username будет связано со столбцом username, не допускающим NULL и с максимальной длиной 50 символов.
Поле age связано со столбцом с SQL-типом INTEGER, по умолчанию равным 18.
2. Аннотация @GeneratedValue
Аннотация @GeneratedValue используется для указания стратегии генерации значений первичного ключа. Она применима к полям, помеченным как @Id.
Основные стратегии:
AUTO — выбор стратегии определяется провайдером JPA.
IDENTITY — генерация значения средствами базы данных.
SEQUENCE — использование последовательности, определенной в базе данных.
TABLE — использование таблицы для хранения значений идентификаторов.
Пример использования:
3. Аннотация @ManyToOne
Аннотация @ManyToOne используется для определения связи "многие к одному". Она обозначает, что текущее поле является ссылкой на другую сущность.
Пример использования:
#Java #Training #Spring #Column #GeneratedValue #ManyToOne
1. Аннотация @Column
Аннотация @Column используется для настройки маппинга поля сущности на столбец таблицы базы данных. С её помощью можно задать имя столбца, его длину, уникальность, возможность быть NULL и другие атрибуты.
Основные параметры:
name — имя столбца в базе данных.
nullable — допускает ли столбец значение NULL.
unique — устанавливает, должны ли значения в столбце быть уникальными.
length — длина для столбцов типа VARCHAR.
columnDefinition — SQL-выражение для явного указания типа столбца.
Пример использования:
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@Entity
public class User {
@Id
private Long id;
@Column(name = "username", nullable = false, unique = true, length = 50)
private String username;
@Column(name = "email", nullable = false, unique = true)
private String email;
@Column(name = "age", columnDefinition = "INTEGER DEFAULT 18")
private int age;
// Геттеры и сеттеры
}
В этом примере мы видим, что:
Поле username будет связано со столбцом username, не допускающим NULL и с максимальной длиной 50 символов.
Поле age связано со столбцом с SQL-типом INTEGER, по умолчанию равным 18.
2. Аннотация @GeneratedValue
Аннотация @GeneratedValue используется для указания стратегии генерации значений первичного ключа. Она применима к полям, помеченным как @Id.
Основные стратегии:
AUTO — выбор стратегии определяется провайдером JPA.
IDENTITY — генерация значения средствами базы данных.
SEQUENCE — использование последовательности, определенной в базе данных.
TABLE — использование таблицы для хранения значений идентификаторов.
Пример использования:
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
// Геттеры и сеттеры
}
Здесь id будет автоматически генерироваться базой данных.
3. Аннотация @ManyToOne
Аннотация @ManyToOne используется для определения связи "многие к одному". Она обозначает, что текущее поле является ссылкой на другую сущность.
Пример использования:
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
@Entity
public class Order {
@Id
private Long id;
private String description;
@ManyToOne
private Customer customer;
// Геттеры и сеттеры
}
Эта аннотация указывает, что множество заказов (Order) могут быть связаны с одним клиентом (Customer).
#Java #Training #Spring #Column #GeneratedValue #ManyToOne
Недавнее обсуждение многопоточности в нашем чате, подтолкнуло меня восполнить недостатки знаний в этой области Java. 🧐
Дополняю темы про распространенные ошибки многопоточности.
Распространенные ошибки многопоточности
Race Condition (Состояние гонки)
Race Condition — это ситуация, когда поведение программы зависит от порядка или своевременности выполнения потоков. Оно возникает, когда несколько потоков одновременно обращаются к одному и тому же ресурсу (например, переменной или объекту), и хотя бы один из них изменяет его.
Пример Race Condition:
Почему Race Condition?
count++ не является атомарной операцией.
Она состоит из трех шагов:
Чтение текущего значения count.
Увеличение значения.
Запись нового значения обратно в переменную.
Если оба потока прочитают одно и то же значение до записи, итоговое значение будет некорректным.
Deadlock (Взаимная блокировка)
Deadlock — ситуация, при которой два или более потоков блокируют друг друга, ожидая освобождения ресурсов.
Пример Deadlock:
Что происходит:
Поток 1 захватывает lock1 и ждет lock2.
Поток 2 захватывает lock2 и ждет lock1.
Оба потока застревают, ожидая освобождения ресурсов друг от друга.
#Java #Training #Multithreading #Medium #Race_Condition #Livelock #Starvation #Thread_Interference #Memory_Consistency_Errors #Multithreading_errors
Дополняю темы про распространенные ошибки многопоточности.
Распространенные ошибки многопоточности
Race Condition (Состояние гонки)
Race Condition — это ситуация, когда поведение программы зависит от порядка или своевременности выполнения потоков. Оно возникает, когда несколько потоков одновременно обращаются к одному и тому же ресурсу (например, переменной или объекту), и хотя бы один из них изменяет его.
Пример Race Condition:
public class Counter {
private int count = 0;
public void increment() {
count++; // Неатомарная операция: чтение, увеличение, запись
}
public int getCount() {
return count;
}
}
public class RaceConditionExample {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final count: " + counter.getCount()); // Ожидаем 2000, но результат может быть меньше
}
}
Почему Race Condition?
count++ не является атомарной операцией.
Она состоит из трех шагов:
Чтение текущего значения count.
Увеличение значения.
Запись нового значения обратно в переменную.
Если оба потока прочитают одно и то же значение до записи, итоговое значение будет некорректным.
Deadlock (Взаимная блокировка)
Deadlock — ситуация, при которой два или более потоков блокируют друг друга, ожидая освобождения ресурсов.
Пример Deadlock:
public class DeadlockExample {
private final Object lock1 = new Object();
private final Object lock2 = new Object();
public void method1() {
synchronized (lock1) {
System.out.println("Thread 1: Holding lock1...");
try { Thread.sleep(50); } catch (InterruptedException e) {}
synchronized (lock2) {
System.out.println("Thread 1: Acquired lock2.");
}
}
}
public void method2() {
synchronized (lock2) {
System.out.println("Thread 2: Holding lock2...");
try { Thread.sleep(50); } catch (InterruptedException e) {}
synchronized (lock1) {
System.out.println("Thread 2: Acquired lock1.");
}
}
}
public static void main(String[] args) {
DeadlockExample demo = new DeadlockExample();
Thread t1 = new Thread(demo::method1);
Thread t2 = new Thread(demo::method2);
t1.start();
t2.start();
}
}
Что происходит:
Поток 1 захватывает lock1 и ждет lock2.
Поток 2 захватывает lock2 и ждет lock1.
Оба потока застревают, ожидая освобождения ресурсов друг от друга.
#Java #Training #Multithreading #Medium #Race_Condition #Livelock #Starvation #Thread_Interference #Memory_Consistency_Errors #Multithreading_errors
Livelock (Живая блокировка)
Livelock похож на Deadlock, но здесь потоки не блокируются, а продолжают изменять свое состояние в попытке избежать конфликта, не продвигаясь дальше.
Пример Livelock:
Что происходит:
Оба потока продолжают "уступать" друг другу, не завершив работу.
Starvation (Голодание)
Starvation — ситуация, когда поток постоянно лишается доступа к ресурсу из-за того, что другие потоки с более высоким приоритетом занимают его.
Причина: Использование приоритетов потоков, где высокоприоритетные потоки блокируют низкоприоритетные.
Thread Interference (Конфликт потоков)
Это ситуация, похожая на Race Condition, когда несколько потоков одновременно читают и изменяют общие данные, приводя к непредсказуемым результатам.
Пример:
Потоки выполняют операции на одной переменной без синхронизации, что приводит к некорректным итоговым значениям.
Memory Consistency Errors (Ошибки согласованности памяти)
Эти ошибки возникают, когда один поток изменяет данные, но другие потоки видят устаревшее состояние этих данных.
Причина: Использование кэша процессора.
Переменная, измененная в одном потоке, может не быть видимой для других потоков.
Решение:
Использование volatile для обеспечения видимости изменений.
Как предотвратить ошибки многопоточности
Использование синхронизации:
synchronized блоки или методы.
ReentrantLock для более гибкого управления блокировкой.
Использование атомарных типов:
Классы из пакета java.util.concurrent.atomic:
AtomicInteger, AtomicBoolean, AtomicReference.
Использование высокоуровневых утилит:
ExecutorService для управления потоками.
CountDownLatch, Semaphore, CyclicBarrier.
Избегание Deadlock:
Всегда захватывать блокировки в одном и том же порядке.
Использование таймаутов при ожидании захвата.
Проверка и отладка:
Инструменты отладки (например, jstack, VisualVM) для анализа состояния потоков.
Логирование текущих блокировок и их владельцев.
#Java #Training #Multithreading #Medium #Race_Condition #Livelock #Starvation #Thread_Interference #Memory_Consistency_Errors #Multithreading_errors
Livelock похож на Deadlock, но здесь потоки не блокируются, а продолжают изменять свое состояние в попытке избежать конфликта, не продвигаясь дальше.
Пример Livelock:
public class LivelockExample {
static class Worker {
private boolean active = true;
public synchronized void work(Worker other) {
while (active) {
System.out.println(Thread.currentThread().getName() + " is working...");
try { Thread.sleep(50); } catch (InterruptedException e) {}
if (other.isActive()) {
System.out.println(Thread.currentThread().getName() + " is waiting...");
continue;
}
break;
}
}
public synchronized void setActive(boolean active) {
this.active = active;
}
public synchronized boolean isActive() {
return active;
}
}
public static void main(String[] args) {
Worker w1 = new Worker();
Worker w2 = new Worker();
Thread t1 = new Thread(() -> w1.work(w2), "Worker 1");
Thread t2 = new Thread(() -> w2.work(w1), "Worker 2");
t1.start();
t2.start();
}
}
Что происходит:
Оба потока продолжают "уступать" друг другу, не завершив работу.
Starvation (Голодание)
Starvation — ситуация, когда поток постоянно лишается доступа к ресурсу из-за того, что другие потоки с более высоким приоритетом занимают его.
Причина: Использование приоритетов потоков, где высокоприоритетные потоки блокируют низкоприоритетные.
Thread Interference (Конфликт потоков)
Это ситуация, похожая на Race Condition, когда несколько потоков одновременно читают и изменяют общие данные, приводя к непредсказуемым результатам.
Пример:
Потоки выполняют операции на одной переменной без синхронизации, что приводит к некорректным итоговым значениям.
Memory Consistency Errors (Ошибки согласованности памяти)
Эти ошибки возникают, когда один поток изменяет данные, но другие потоки видят устаревшее состояние этих данных.
Причина: Использование кэша процессора.
Переменная, измененная в одном потоке, может не быть видимой для других потоков.
Решение:
Использование volatile для обеспечения видимости изменений.
private static volatile boolean running = true;
public void run() {
while (running) {
// Выполняем задачу
}
}
Как предотвратить ошибки многопоточности
Использование синхронизации:
synchronized блоки или методы.
ReentrantLock для более гибкого управления блокировкой.
Использование атомарных типов:
Классы из пакета java.util.concurrent.atomic:
AtomicInteger, AtomicBoolean, AtomicReference.
Использование высокоуровневых утилит:
ExecutorService для управления потоками.
CountDownLatch, Semaphore, CyclicBarrier.
Избегание Deadlock:
Всегда захватывать блокировки в одном и том же порядке.
Использование таймаутов при ожидании захвата.
Проверка и отладка:
Инструменты отладки (например, jstack, VisualVM) для анализа состояния потоков.
Логирование текущих блокировок и их владельцев.
#Java #Training #Multithreading #Medium #Race_Condition #Livelock #Starvation #Thread_Interference #Memory_Consistency_Errors #Multithreading_errors
Что выведет код?
#Tasks
class Parent { }
class Child extends Parent { }
public class Task191124_1 {
public static void main(String[] args) {
Parent obj1 = new Parent();
Parent obj2 = new Child();
Child obj3 = new Child();
System.out.println(obj1 instanceof Parent);
System.out.println(obj2 instanceof Child);
System.out.println(obj3 instanceof Parent);
System.out.println(obj1 instanceof Child);
}
}
#Tasks
Варианты ответа:
Anonymous Quiz
17%
true false true false
33%
true true false false
50%
true true true false
0%
true true true true
Аннотации JPA: @OneToOne, @ManyToMany, @JoinColumn, @Lob, @Query, @Modifying, @EnableJpaRepositories
1. @OneToOne
Аннотация @OneToOne используется для определения связи "один к одному" между сущностями. Это может быть, например, связь между пользователем и его профилем.
2. @ManyToMany
@ManyToMany обозначает связь "многие ко многим". Это используется, когда несколько сущностей одной таблицы могут быть связаны с несколькими сущностями другой таблицы.
3. @JoinColumn
Аннотация @JoinColumn задаёт внешний ключ для связи. Она может использоваться с аннотациями @OneToOne и @ManyToOne.
4. @Lob
@Lob используется для маппинга больших объектов, таких как текстовые или бинарные данные.
5. @Query
Аннотация @Query позволяет задавать JPQL или SQL-запросы прямо в репозитории.
6. @Modifying
Используется вместе с @Query для выполнения операций обновления или удаления данных.
7. @EnableJpaRepositories
Эта аннотация активирует JPA-репозитории в Spring Boot.
#Java #Training #Spring #OneToOne #ManyToMany #JoinColumn #Lob #Query #Modifying #EnableJpaRepositories
1. @OneToOne
Аннотация @OneToOne используется для определения связи "один к одному" между сущностями. Это может быть, например, связь между пользователем и его профилем.
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne
@JoinColumn(name = "profile_id", referencedColumnName = "id")
private Profile profile;
}
@Entity
public class Profile {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String bio;
}
Здесь связь между User и Profile устанавливается через внешний ключ profile_id.
2. @ManyToMany
@ManyToMany обозначает связь "многие ко многим". Это используется, когда несколько сущностей одной таблицы могут быть связаны с несколькими сущностями другой таблицы.
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToMany
@JoinTable(
name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id")
)
private List<Course> courses;
}
@Entity
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
@ManyToMany(mappedBy = "courses")
private List<Student> students;
}
Связь осуществляется через промежуточную таблицу student_course.
3. @JoinColumn
Аннотация @JoinColumn задаёт внешний ключ для связи. Она может использоваться с аннотациями @OneToOne и @ManyToOne.
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "customer_id", nullable = false)
private Customer customer;
}
Здесь customer_id в таблице Order будет внешним ключом, ссылающимся на таблицу Customer.
4. @Lob
@Lob используется для маппинга больших объектов, таких как текстовые или бинарные данные.
@Entity
public class Document {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Lob
private String content; // Для больших текстов
@Lob
private byte[] fileData; // Для бинарных данных
}
5. @Query
Аннотация @Query позволяет задавать JPQL или SQL-запросы прямо в репозитории.
public interface UserRepository extends JpaRepository<User, Long> {
@Query("SELECT u FROM User u WHERE u.email = :email")
User findByEmail(@Param("email") String email);
}
6. @Modifying
Используется вместе с @Query для выполнения операций обновления или удаления данных.
public interface UserRepository extends JpaRepository<User, Long> {
@Modifying
@Query("UPDATE User u SET u.name = :name WHERE u.id = :id")
void updateUserName(@Param("id") Long id, @Param("name") String name);
}
7. @EnableJpaRepositories
Эта аннотация активирует JPA-репозитории в Spring Boot.
@Configuration
@EnableJpaRepositories(basePackages = "com.example.repository")
public class AppConfig {
}
#Java #Training #Spring #OneToOne #ManyToMany #JoinColumn #Lob #Query #Modifying #EnableJpaRepositories
Аннотации JPA: @Embeddable, @Embedded, @ElementCollection, @Inheritance, @Cacheable, @Lock, @EntityListeners, @SQLInsert, @SQLUpdate, @SQLDelete
1. @Embeddable и @Embedded
Аннотация @Embeddable обозначает класс, который будет встраиваться в другие сущности, а @Embedded — указывает, что поле встраивает такой класс.
2. @ElementCollection
Используется для хранения коллекций простых типов или встраиваемых объектов.
3. @Inheritance
Настраивает стратегию наследования для сущностей.
4. @Cacheable
Обозначает, что сущность может быть закеширована.
5. @Lock
Используется для управления блокировками данных.
6. @EntityListeners
Позволяет подключать слушатели для отслеживания событий сущности.
7. @SQLInsert, @SQLUpdate, @SQLDelete
Эти аннотации позволяют задать кастомные SQL-запросы для операций вставки, обновления и удаления.
#Java #Training #Spring #Embeddable, #Embedded, #ElementCollection, #Inheritance, #Cacheable, #Lock, #EntityListeners, #SQLInsert, #SQLUpdate, #SQLDelete
1. @Embeddable и @Embedded
Аннотация @Embeddable обозначает класс, который будет встраиваться в другие сущности, а @Embedded — указывает, что поле встраивает такой класс.
@Embeddable
public class Address {
private String street;
private String city;
}
@Entity
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Embedded
private Address address;
}
2. @ElementCollection
Используется для хранения коллекций простых типов или встраиваемых объектов.
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ElementCollection
private List<String> tags;
}
3. @Inheritance
Настраивает стратегию наследования для сущностей.
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Vehicle {
@Id
private Long id;
}
@Entity
public class Car extends Vehicle {
private int seatingCapacity;
}
4. @Cacheable
Обозначает, что сущность может быть закеширована.
@Entity
@Cacheable
public class Product {
@Id
private Long id;
private String name;
}
5. @Lock
Используется для управления блокировками данных.
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT u FROM User u WHERE u.id = :id")
User findForUpdate(@Param("id") Long id);
6. @EntityListeners
Позволяет подключать слушатели для отслеживания событий сущности.
@Entity
@EntityListeners(AuditListener.class)
public class Order {
@Id
private Long id;
}
7. @SQLInsert, @SQLUpdate, @SQLDelete
Эти аннотации позволяют задать кастомные SQL-запросы для операций вставки, обновления и удаления.
@SQLInsert(sql = "INSERT INTO user_audit (id, username) VALUES (?, ?)")
@SQLDelete(sql = "DELETE FROM user_audit WHERE id = ?")
@Entity
public class UserAudit {
@Id
private Long id;
}
#Java #Training #Spring #Embeddable, #Embedded, #ElementCollection, #Inheritance, #Cacheable, #Lock, #EntityListeners, #SQLInsert, #SQLUpdate, #SQLDelete
Что выведет код?
#Tasks
import java.math.BigDecimal;
public class Task201124_1 {
public static void main(String[] args) {
BigDecimal num1 = new BigDecimal("3");
BigDecimal num2 = new BigDecimal("2");
BigDecimal sum = num1.add(num2);
BigDecimal product = num1.multiply(num2);
BigDecimal result = sum.subtract(product).divide(new BigDecimal("1.0"), 10, BigDecimal.ROUND_HALF_UP);
System.out.println(result);
}
}
#Tasks
Сущности в JPA
В Java Persistence API (JPA) сущности представляют собой объекты, которые будут храниться в базе данных. Эти объекты маппируются на таблицы базы данных и могут содержать атрибуты, которые соответствуют столбцам таблицы.
1. Основные принципы сущности в JPA
Сущности JPA — это классы, которые автоматически маппируются на таблицы базы данных.
Важно понимать, что сущности:
Являются Java POJO (Plain Old Java Object) классами, которые должны иметь конструктор без параметров.
Должны быть аннотированы аннотацией @Entity.
Каждый объект сущности будет соответствовать одной строке в базе данных.
Для работы с сущностью в базе данных используется Entity Manager, который управляет состоянием объектов и их персистенцией.
2. Основные аннотации для сущностей
2.1 @Entity
Аннотация @Entity указывает, что класс является сущностью, которая будет маппироваться на таблицу в базе данных.
Класс, аннотированный @Entity, будет автоматически сопоставлен с таблицей в базе данных.
Если не указано, имя таблицы будет автоматически сформировано из имени класса.
2.2 @Table
Аннотация @Table используется для настройки таблицы, с которой будет работать сущность. Вы можете указать имя таблицы, схему и ограничения.
2.3 @Id
Аннотация @Id указывает на поле, которое является первичным ключом для сущности.
3. Стратегии генерации значений для первичного ключа
3.1 GenerationType.IDENTITY
Эта стратегия используется для автоматической генерации значений в столбце, обычно используется в базе данных с поддержкой автоинкремента.
3.2 GenerationType.SEQUENCE
Используется для генерации уникальных значений через последовательности базы данных.
3.3 GenerationType.TABLE
Использует специальную таблицу для генерации уникальных значений.
4. Маппинг полей сущности на столбцы таблицы
4.1 @Column
Аннотация @Column используется для маппинга поля сущности на столбец таблицы.
4.2 @Lob
Аннотация @Lob используется для хранения больших объектов (например, текста или бинарных данных). Это может быть полезно для хранения изображений, файлов или больших текстовых полей.
4.3 @Transient
Аннотация @Transient используется для исключения поля из маппинга. Это поле не будет сохраняться в базе данных.
#Java #Training #Spring #JPA_Entity
В Java Persistence API (JPA) сущности представляют собой объекты, которые будут храниться в базе данных. Эти объекты маппируются на таблицы базы данных и могут содержать атрибуты, которые соответствуют столбцам таблицы.
1. Основные принципы сущности в JPA
Сущности JPA — это классы, которые автоматически маппируются на таблицы базы данных.
Важно понимать, что сущности:
Являются Java POJO (Plain Old Java Object) классами, которые должны иметь конструктор без параметров.
Должны быть аннотированы аннотацией @Entity.
Каждый объект сущности будет соответствовать одной строке в базе данных.
Для работы с сущностью в базе данных используется Entity Manager, который управляет состоянием объектов и их персистенцией.
2. Основные аннотации для сущностей
2.1 @Entity
Аннотация @Entity указывает, что класс является сущностью, которая будет маппироваться на таблицу в базе данных.
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
// геттеры и сеттеры
}
Класс, аннотированный @Entity, будет автоматически сопоставлен с таблицей в базе данных.
Если не указано, имя таблицы будет автоматически сформировано из имени класса.
2.2 @Table
Аннотация @Table используется для настройки таблицы, с которой будет работать сущность. Вы можете указать имя таблицы, схему и ограничения.
@Entity
@Table(name = "users", schema = "public")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
}
Атрибуты name и schema позволяют указать, на какую таблицу и в какой схеме будет маппироваться класс.
2.3 @Id
Аннотация @Id указывает на поле, которое является первичным ключом для сущности.
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
Поле, помеченное @Id, будет использоваться как первичный ключ таблицы.
Аннотация @GeneratedValue указывает стратегию генерации значений первичного ключа.
3. Стратегии генерации значений для первичного ключа
3.1 GenerationType.IDENTITY
Эта стратегия используется для автоматической генерации значений в столбце, обычно используется в базе данных с поддержкой автоинкремента.
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
3.2 GenerationType.SEQUENCE
Используется для генерации уникальных значений через последовательности базы данных.
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_seq")
@SequenceGenerator(name = "user_seq", sequenceName = "user_sequence")
private Long id;
3.3 GenerationType.TABLE
Использует специальную таблицу для генерации уникальных значений.
@GeneratedValue(strategy = GenerationType.TABLE, generator = "id_gen")
@TableGenerator(name = "id_gen", table = "id_generator")
private Long id;
4. Маппинг полей сущности на столбцы таблицы
4.1 @Column
Аннотация @Column используется для маппинга поля сущности на столбец таблицы.
@Column(name = "username", nullable = false, unique = true, length = 50)
private String username;
name: имя столбца.
nullable: указывает, может ли столбец быть пустым.
unique: задает уникальность значения столбца.
length: максимальная длина строкового значения.
4.2 @Lob
Аннотация @Lob используется для хранения больших объектов (например, текста или бинарных данных). Это может быть полезно для хранения изображений, файлов или больших текстовых полей.
@Lob
private String description;
4.3 @Transient
Аннотация @Transient используется для исключения поля из маппинга. Это поле не будет сохраняться в базе данных.
@Transient
private String temporaryData;
#Java #Training #Spring #JPA_Entity
5. Работа с жизненным циклом сущности
5.1 @PrePersist, @PostPersist
Эти аннотации позволяют реализовывать методы, которые вызываются перед или после вставки сущности в базу данных.
#Java #Training #Spring #JPA_Entity
5.1 @PrePersist, @PostPersist
Эти аннотации позволяют реализовывать методы, которые вызываются перед или после вставки сущности в базу данных.
@Entity
public class Order {
@Id
private Long id;
@PrePersist
public void prePersist() {
System.out.println("Before persisting the Order");
}
@PostPersist
public void postPersist() {
System.out.println("After persisting the Order");
}
}
#Java #Training #Spring #JPA_Entity
Репозитории в Spring Data: интерфейс CrudRepository и JpaRepository
В экосистеме Spring Data важнейшую роль играют репозитории, которые позволяют работать с данными, не пиша сложного SQL-кода. Два ключевых интерфейса, которые используются чаще всего, — это CrudRepository и JpaRepository.
CrudRepository
CrudRepository — это базовый интерфейс для работы с CRUD-операциями (Create, Read, Update, Delete). Он предоставляет набор стандартных методов, которые можно использовать для управления сущностями.
Основные методы CrudRepository:
save(S entity): Сохраняет сущность.
findById(ID id): Находит сущность по ID.
existsById(ID id): Проверяет существование сущности с заданным ID.
findAll(): Возвращает все сущности.
deleteById(ID id): Удаляет сущность по ID.
deleteAll(): Удаляет все сущности.
Пример использования CrudRepository:
JpaRepository
JpaRepository расширяет возможности CrudRepository и добавляет дополнительные методы для работы с коллекциями и пагинацией. Этот интерфейс является частью Spring Data JPA и более мощным инструментом.
Основные методы JpaRepository:
saveAll(Iterable<S> entities): Сохраняет коллекцию сущностей.
findAll(Sort sort): Возвращает все сущности с сортировкой.
findAll(Pageable pageable): Возвращает сущности с постраничной разбивкой.
flush(): Принудительно записывает изменения в базу данных.
saveAndFlush(S entity): Сохраняет сущность и немедленно записывает изменения.
Пример использования JpaRepository:
Теперь можно использовать более сложные запросы, такие как сортировка и пагинация:
Основные отличия CrudRepository и JpaRepository:
JpaRepository предоставляет больше методов, что полезно для сложных операций.
CrudRepository минималистичен, подходит для простых операций CRUD.
JpaRepository работает на базе JPA, добавляя функциональность для сортировки и пагинации.
Использование JpaRepository предпочтительно, если проект использует JPA и предполагает расширенные функции.
Пример работы с JpaRepository
Предположим, у нас есть сущность Order:
Теперь создадим репозиторий:
Мы можем легко сохранять и получать данные:
#Java #Training #Spring #CrudRepository #JpaRepository
В экосистеме Spring Data важнейшую роль играют репозитории, которые позволяют работать с данными, не пиша сложного SQL-кода. Два ключевых интерфейса, которые используются чаще всего, — это CrudRepository и JpaRepository.
CrudRepository
CrudRepository — это базовый интерфейс для работы с CRUD-операциями (Create, Read, Update, Delete). Он предоставляет набор стандартных методов, которые можно использовать для управления сущностями.
Основные методы CrudRepository:
save(S entity): Сохраняет сущность.
findById(ID id): Находит сущность по ID.
existsById(ID id): Проверяет существование сущности с заданным ID.
findAll(): Возвращает все сущности.
deleteById(ID id): Удаляет сущность по ID.
deleteAll(): Удаляет все сущности.
Пример использования CrudRepository:
import org.springframework.data.repository.CrudRepository;
public interface UserRepository extends CrudRepository<User, Long> {
}
В этом примере UserRepository предоставляет все стандартные CRUD-операции для работы с сущностью User.
JpaRepository
JpaRepository расширяет возможности CrudRepository и добавляет дополнительные методы для работы с коллекциями и пагинацией. Этот интерфейс является частью Spring Data JPA и более мощным инструментом.
Основные методы JpaRepository:
saveAll(Iterable<S> entities): Сохраняет коллекцию сущностей.
findAll(Sort sort): Возвращает все сущности с сортировкой.
findAll(Pageable pageable): Возвращает сущности с постраничной разбивкой.
flush(): Принудительно записывает изменения в базу данных.
saveAndFlush(S entity): Сохраняет сущность и немедленно записывает изменения.
Пример использования JpaRepository:
import org.springframework.data.jpa.repository.JpaRepository;
public interface ProductRepository extends JpaRepository<Product, Long> {
}
Теперь можно использовать более сложные запросы, такие как сортировка и пагинация:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
public Page<Product> getProducts(int page, int size) {
return productRepository.findAll(PageRequest.of(page, size));
}
}
Основные отличия CrudRepository и JpaRepository:
JpaRepository предоставляет больше методов, что полезно для сложных операций.
CrudRepository минималистичен, подходит для простых операций CRUD.
JpaRepository работает на базе JPA, добавляя функциональность для сортировки и пагинации.
Использование JpaRepository предпочтительно, если проект использует JPA и предполагает расширенные функции.
Пример работы с JpaRepository
Предположим, у нас есть сущность Order:
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
@Entity
public class Order {
@Id
@GeneratedValue
private Long id;
private String description;
private double price;
// getters and setters
}
Теперь создадим репозиторий:
import org.springframework.data.jpa.repository.JpaRepository;
public interface OrderRepository extends JpaRepository<Order, Long> {
}
Мы можем легко сохранять и получать данные:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
public Order saveOrder(Order order) {
return orderRepository.save(order);
}
public List<Order> getAllOrders() {
return orderRepository.findAll();
}
}
#Java #Training #Spring #CrudRepository #JpaRepository
Продолжаем устранять пробелы в многопоточке Java. Сегодня рассмотрим интерфейс Callable.
Callable
Callable — это функциональный интерфейс в Java, который представляет задачу, выполняемую в отдельном потоке. Он был введен в Java 5 вместе с пакетами для многозадачности (java.util.concurrent), и его основное назначение — предоставить способ выполнения асинхронных операций, которые могут вернуть результат.
1. Основные особенности Callable
Интерфейс Callable аналогичен интерфейсу Runnable, но с двумя важными отличиями:
Возвращаемое значение: В отличие от Runnable, который не возвращает значения (void run()), метод call() интерфейса Callable может возвращать результат. Это позволяет возвращать какие-либо данные (например, результат вычислений или ошибку).
Исключения: Метод call() может бросать исключения, в отличие от метода run() интерфейса Runnable, который не может выбрасывать проверяемые исключения.
Возвращаемое значение: Метод call() возвращает объект типа V (генерик), который может быть любым типом. Это возвращаемое значение удобно для получения результатов выполнения асинхронных задач.
Использование с ExecutorService:
Задачи, реализующие Callable, часто выполняются через ExecutorService, который предоставляет методы для асинхронного выполнения таких задач.
2. Методы интерфейса Callable
call() — это основной метод интерфейса. Он выполняет задачу и возвращает результат типа V. Также этот метод может выбрасывать проверяемые исключения (Exception), что отличает его от метода run() интерфейса Runnable, который не может этого делать.
3. Основные классы и интерфейсы для работы с Callable
Чтобы эффективно использовать интерфейс Callable, в Java существует несколько классов и интерфейсов для работы с многозадачностью:
ExecutorService — интерфейс для управления пулом потоков и выполнения задач в асинхронном режиме.
Future<V> — интерфейс, который представляет результат асинхронной задачи. Он используется для получения результата выполнения Callable после завершения его работы. Через объект Future можно проверить статус выполнения задачи, отменить её или получить результат (если задача завершена).
Пример использования Callable и ExecutorService:
4. Методы интерфейса Future
Объект Future, который возвращается методом submit() объекта ExecutorService, предоставляет несколько полезных методов для работы с результатом асинхронной задачи:
get(): Блокирует текущий поток до получения результата выполнения задачи. Если задача завершена с ошибкой, этот метод выбрасывает ExecutionException.
get(long timeout, TimeUnit unit): Блокирует текущий поток до получения результата или до истечения времени ожидания.
cancel(boolean mayInterruptIfRunning): Отменяет задачу. Если задача не начала выполнение, она будет отменена. Если она уже выполняется, её можно прервать, если указан параметр mayInterruptIfRunning = true.
isCancelled(): Проверяет, была ли задача отменена.
isDone(): Проверяет, завершена ли задача (независимо от того, успешно ли она завершилась).
#Java #Training #Multithreading #Callable
Callable
Callable — это функциональный интерфейс в Java, который представляет задачу, выполняемую в отдельном потоке. Он был введен в Java 5 вместе с пакетами для многозадачности (java.util.concurrent), и его основное назначение — предоставить способ выполнения асинхронных операций, которые могут вернуть результат.
1. Основные особенности Callable
Интерфейс Callable аналогичен интерфейсу Runnable, но с двумя важными отличиями:
Возвращаемое значение: В отличие от Runnable, который не возвращает значения (void run()), метод call() интерфейса Callable может возвращать результат. Это позволяет возвращать какие-либо данные (например, результат вычислений или ошибку).
Исключения: Метод call() может бросать исключения, в отличие от метода run() интерфейса Runnable, который не может выбрасывать проверяемые исключения.
Возвращаемое значение: Метод call() возвращает объект типа V (генерик), который может быть любым типом. Это возвращаемое значение удобно для получения результатов выполнения асинхронных задач.
Использование с ExecutorService:
Задачи, реализующие Callable, часто выполняются через ExecutorService, который предоставляет методы для асинхронного выполнения таких задач.
2. Методы интерфейса Callable
call() — это основной метод интерфейса. Он выполняет задачу и возвращает результат типа V. Также этот метод может выбрасывать проверяемые исключения (Exception), что отличает его от метода run() интерфейса Runnable, который не может этого делать.
public interface Callable<V> {
V call() throws Exception;
}
3. Основные классы и интерфейсы для работы с Callable
Чтобы эффективно использовать интерфейс Callable, в Java существует несколько классов и интерфейсов для работы с многозадачностью:
ExecutorService — интерфейс для управления пулом потоков и выполнения задач в асинхронном режиме.
Future<V> — интерфейс, который представляет результат асинхронной задачи. Он используется для получения результата выполнения Callable после завершения его работы. Через объект Future можно проверить статус выполнения задачи, отменить её или получить результат (если задача завершена).
Пример использования Callable и ExecutorService:
import java.util.concurrent.*;
public class CallableExample {
public static void main(String[] args) {
// Создаем ExecutorService с пулом потоков
ExecutorService executor = Executors.newFixedThreadPool(2);
// Задача, которая возвращает результат
Callable<Integer> task = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
// Пример вычислений
return 123;
}
};
// Выполняем задачу и получаем объект Future
Future<Integer> future = executor.submit(task);
try {
// Получаем результат выполнения задачи
Integer result = future.get(); // блокирует текущий поток до получения результата
System.out.println("Результат: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
executor.shutdown();
}
}
}
4. Методы интерфейса Future
Объект Future, который возвращается методом submit() объекта ExecutorService, предоставляет несколько полезных методов для работы с результатом асинхронной задачи:
get(): Блокирует текущий поток до получения результата выполнения задачи. Если задача завершена с ошибкой, этот метод выбрасывает ExecutionException.
get(long timeout, TimeUnit unit): Блокирует текущий поток до получения результата или до истечения времени ожидания.
cancel(boolean mayInterruptIfRunning): Отменяет задачу. Если задача не начала выполнение, она будет отменена. Если она уже выполняется, её можно прервать, если указан параметр mayInterruptIfRunning = true.
isCancelled(): Проверяет, была ли задача отменена.
isDone(): Проверяет, завершена ли задача (независимо от того, успешно ли она завершилась).
#Java #Training #Multithreading #Callable
5. Преимущества использования Callable
Возврат результата: В отличие от Runnable, который не возвращает результата, Callable может возвращать значения, что делает его полезным для вычислений, которые должны вернуть результат.
Обработка исключений: Callable позволяет методам выбрасывать проверяемые исключения, что полезно для обработки ошибок в многозадачных приложениях.
Параллельное выполнение: Использование ExecutorService с задачами типа Callable позволяет эффективно управлять пулом потоков, распределяя задачи между потоками.
6. Нюансы использования Callable
Блокировка с get(): Важно помнить, что метод get() блокирует текущий поток до тех пор, пока задача не завершится. Если вы вызываете get() на множестве задач, это может привести к значительным задержкам, если задачи не завершены вовремя.
Исключения в call(): Поскольку метод call() может выбрасывать исключения, важно правильно их обрабатывать в блоке try-catch, особенно если задача выполняет долгосрочную или ресурсозатратную операцию.
Параллельность: Если задач несколько, ExecutorService с пулом потоков позволяет выполнять их параллельно, но стоит быть осторожным с использованием ресурсов, так как слишком много потоков может привести к перегрузке системы.
Атомарность операций: Если задачи выполняют изменения общих данных, важно учитывать синхронизацию, чтобы избежать конфликтов между потоками.
Использование с Callable и Future для делегирования работы: Параллельное выполнение задач через ExecutorService и использование объектов Future позволяет строить более сложные асинхронные системы с возможностью отмены задач, получения результатов и обработки ошибок.
7. Пример использования Callable с возвращаемыми результатами и исключениями
#Java #Training #Medium #Multithreading #Callable
Возврат результата: В отличие от Runnable, который не возвращает результата, Callable может возвращать значения, что делает его полезным для вычислений, которые должны вернуть результат.
Обработка исключений: Callable позволяет методам выбрасывать проверяемые исключения, что полезно для обработки ошибок в многозадачных приложениях.
Параллельное выполнение: Использование ExecutorService с задачами типа Callable позволяет эффективно управлять пулом потоков, распределяя задачи между потоками.
6. Нюансы использования Callable
Блокировка с get(): Важно помнить, что метод get() блокирует текущий поток до тех пор, пока задача не завершится. Если вы вызываете get() на множестве задач, это может привести к значительным задержкам, если задачи не завершены вовремя.
Исключения в call(): Поскольку метод call() может выбрасывать исключения, важно правильно их обрабатывать в блоке try-catch, особенно если задача выполняет долгосрочную или ресурсозатратную операцию.
Параллельность: Если задач несколько, ExecutorService с пулом потоков позволяет выполнять их параллельно, но стоит быть осторожным с использованием ресурсов, так как слишком много потоков может привести к перегрузке системы.
Атомарность операций: Если задачи выполняют изменения общих данных, важно учитывать синхронизацию, чтобы избежать конфликтов между потоками.
Использование с Callable и Future для делегирования работы: Параллельное выполнение задач через ExecutorService и использование объектов Future позволяет строить более сложные асинхронные системы с возможностью отмены задач, получения результатов и обработки ошибок.
7. Пример использования Callable с возвращаемыми результатами и исключениями
import java.util.concurrent.*;
public class CallableWithException {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
Callable<String> task = () -> {
// Исключение для демонстрации обработки ошибок
if (true) {
throw new IllegalArgumentException("Произошла ошибка");
}
return "Успешно выполнено!";
};
Future<String> future = executor.submit(task);
try {
String result = future.get(); // Это вызовет исключение, если задача выбросит ошибку
System.out.println("Результат: " + result);
} catch (ExecutionException e) {
System.out.println("Ошибка выполнения задачи: " + e.getCause());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
executor.shutdown();
}
}
}
#Java #Training #Medium #Multithreading #Callable
Что выведет код?
#Tasks
import java.util.*;
public class Task211124_1 {
public static void main(String[] args) {
List<String> items = Arrays.asList("A", "B", "C", "D", "E", "F", "G", "H", "I", "J");
int pageSize = 3;
int page = 3;
List<String> pageItems = paginate(items, page, pageSize);
System.out.println(pageItems);
}
public static List<String> paginate(List<String> items, int page, int pageSize) {
int start = (page - 1) * pageSize;
int end = Math.min(start + pageSize, items.size());
return items.subList(start, end);
}
}
#Tasks