Какие используешь аннотации при написании Entity
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Аннотации при написании Entity в Java
Аннотации в JPA (Java Persistence API) и Hibernate — это декларативный способ определить структуру базы данных и поведение сущностей. Правильное использование аннотаций критично для создания надёжного слоя работы с данными.
Основные аннотации для Entity
@Entity — базовая аннотация, которая определяет класс как JPA сущность
@Entity
@Table(name = "users") // имя таблицы в БД
public class User {
// Это класс, который будет отображён на таблицу
}
@Id — определяет первичный ключ
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // автоинкремент
private Long id;
}
@GeneratedValue — способ генерации ID
public class User {
// IDENTITY: БД генерирует (MySQL, PostgreSQL)
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// SEQUENCE: использует sequence (Oracle, PostgreSQL)
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "user_sequence")
@SequenceGenerator(name = "user_sequence",
sequenceName = "user_seq",
allocationSize = 1)
private Long id;
// UUID: генерирует UUID
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;
}
@Column — конфигурирует колонку БД
@Entity
public class User {
@Id
private Long id;
@Column(name = "email_address", // имя колонки
unique = true, // уникальность
nullable = false, // не может быть null
length = 255) // длина строки
private String email;
@Column(columnDefinition = "VARCHAR(500) DEFAULT 'N/A'")
private String description;
@Column(updatable = false) // может быть установлена, но не обновлена
private LocalDateTime createdAt;
}
Отношения между Entity
@OneToMany — один ко многим
@Entity
public class User {
@Id
private Long id;
// Один User имеет много Orders
@OneToMany(mappedBy = "user", // поле в Order, которое ссылается на User
cascade = CascadeType.ALL, // удалить User -> удалить его Orders
orphanRemoval = true, // удалить Order если удалить из коллекции
fetch = FetchType.LAZY) // ленивая загрузка
private List<Order> orders = new ArrayList<>();
}
@Entity
public class Order {
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY) // Много Orders относятся к одному User
@JoinColumn(name = "user_id", nullable = false) // внешний ключ
private User user;
}
@ManyToOne — много к одному
@Entity
public class OrderItem {
@Id
private Long id;
@ManyToOne
@JoinColumn(name = "order_id", nullable = false)
private Order order;
}
@ManyToMany — многие ко многим
@Entity
public class Student {
@Id
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
private Long id;
@ManyToMany(mappedBy = "courses")
private List<Student> students;
}
@OneToOne — один к одному
@Entity
public class User {
@Id
private Long id;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "profile_id", unique = true)
private UserProfile profile;
}
@Entity
public class UserProfile {
@Id
private Long id;
@OneToOne(mappedBy = "profile")
private User user;
}
Валидация данных
Аннотации из javax.validation (Bean Validation)
@Entity
public class User {
@Id
private Long id;
@NotBlank(message = "Email не может быть пустым") // не null и не пусто
@Email // валидный email
@Column(unique = true)
private String email;
@NotNull // не может быть null
@Min(18) // минимальное значение
@Max(120) // максимальное значение
private Integer age;
@NotEmpty // коллекция не пуста
@Size(min = 1, max = 10) // размер коллекции
private List<String> hobbies;
@Pattern(regexp = "^\\d{10}$") // регулярное выражение
private String phoneNumber;
}
Специальные аннотации для дат и времени
@Entity
public class Order {
@Id
private Long id;
@CreationTimestamp // Hibernate: установить при создании
@Column(updatable = false)
private LocalDateTime createdAt;
@UpdateTimestamp // Hibernate: обновлять при изменении
private LocalDateTime updatedAt;
// JPA способ
@Column(updatable = false)
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime createdAtJpa;
}
Важные аннотации для поведения
@PrePersist / @PostPersist — хуки жизненного цикла
@Entity
public class User {
@Id
private Long id;
private String email;
private LocalDateTime createdAt;
@PrePersist // вызывается ДО сохранения в БД
protected void onCreate() {
this.createdAt = LocalDateTime.now();
}
@PostPersist // вызывается ПОСЛЕ сохранения в БД
protected void onCreated() {
System.out.println("User saved: " + this.id);
}
}
@PreUpdate / @PostUpdate — при обновлении
@Entity
public class User {
private LocalDateTime updatedAt;
@PreUpdate
protected void onUpdate() {
this.updatedAt = LocalDateTime.now();
}
}
@Version — для оптимистичной блокировки
@Entity
public class Product {
@Id
private Long id;
@Version // Hibernate отслеживает версию для concurrent updates
private Long version;
private String name;
private BigDecimal price;
}
Дополнительные аннотации
@Transient — поле НЕ сохраняется в БД
@Entity
public class User {
@Id
private Long id;
private String name;
@Transient // это поле не будет в БД
private String fullName; // может быть вычисляемым
}
@Lob — для больших данных (BLOB/CLOB)
@Entity
public class Document {
@Id
private Long id;
@Lob // Large Object
@Column(columnDefinition = "LONGTEXT")
private String content; // большой текст
@Lob
private byte[] fileData; // бинарные данные
}
@Enumerated — для enum полей
public enum UserRole {
ADMIN, USER, GUEST
}
@Entity
public class User {
@Id
private Long id;
@Enumerated(EnumType.STRING) // сохранять как строка ("ADMIN")
private UserRole role; // или EnumType.ORDINAL (0,1,2)
}
@JsonIgnore — для исключения при сериализации
@Entity
public class User {
@Id
private Long id;
private String email;
@JsonIgnore
private String passwordHash; // не будет в JSON
}
Полный пример Entity
@Entity
@Table(name = "users",
indexes = {@Index(name = "idx_email", columnList = "email")})
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank
@Column(nullable = false, length = 255)
private String name;
@NotBlank
@Email
@Column(unique = true, nullable = false)
private String email;
@NotNull
@Min(18)
private Integer age;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private UserRole role;
@CreationTimestamp
@Column(updatable = false)
private LocalDateTime createdAt;
@UpdateTimestamp
private LocalDateTime updatedAt;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Order> orders = new ArrayList<>();
@Version
private Long version;
@PrePersist
protected void onCreate() {
if (this.createdAt == null) {
this.createdAt = LocalDateTime.now(UTC);
}
}
}
Best Practices при использовании аннотаций
✓ Делай:
- Используй
@NotNull,@NotBlankдля обязательных полей - Указывай
cascade = CascadeType.ALLдля parent-child отношений - Используй
FetchType.LAZYдля больших коллекций - Добавляй
@Columnсnullable = falseдля важных полей - Индексируй часто используемые для поиска поля
- Используй
@CreationTimestampи@UpdateTimestamp
✗ Не делай:
- Не забывай
cascadeиorphanRemovalдля отношений - Не используй
FetchType.EAGERбез необходимости (N+1 проблема) - Не делай огромные
@OneToManyколлекции без фильтрации - Не забывай
@JsonIgnoreдля чувствительных данных - Не используй примитивные типы вместо обёрток (int вместо Integer)
Выводы
Правильное использование аннотаций JPA/Hibernate:
- Определяет структуру БД декларативно
- Автоматизирует управление отношениями
- Предотвращает ошибки через валидацию
- Улучшает производительность через ленивую загрузку
- Делает код более поддерживаемым и понятным
Это основа для создания надёжного слоя работы с данными в Java приложениях.