← Назад к вопросам

Какие используешь аннотации при написании Entity

1.6 Junior🔥 281 комментариев
#ORM и Hibernate

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Аннотации при написании 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 приложениях.

Какие используешь аннотации при написании Entity | PrepBro