Основные аннотации JPA
@Entity – помечает класс как сущность JPA, соответствующую таблице. Класс с этой аннотацией должен иметь идентификатор (первичный ключ) и удовлетворять ряду требований (конструктор без параметров, не финальный и т.д.).
@Table(name = "TABLE_NAME") – указывает имя таблицы в базе данных, на которую отображается данный класс. Если не задано, по умолчанию таблица будет названа как класс (с возможной конвертацией регистра, в JPA стандарт – без учета регистра, зависит от провайдера).
@Id – помечает поле или метод, как идентификатор сущности (primary key). Каждая сущность обязана иметь одно или несколько полей @Id (сложный ключ – несколько, тогда обычно используют @IdClass или составной embed).
@GeneratedValue(strategy = ...) – ставится вместе с @Id, указывает, как генерируется значение первичного ключа. Стратегии: AUTO (по умолчанию, провайдер сам выберет способ, обычно последовательность или таблица), IDENTITY (для автоинкрементных столбцов, например MySQL), SEQUENCE (использовать последовательность Sequence в БД, обычно для Oracle, PostgreSQL), TABLE (устарело – имитация последовательности через отдельную таблицу).
@Column – позволяет настроить отображение поля на колонку. Можно указать имя колонки (@Column(name="first_name")), тип (например, длину для строк length=100, или precision/scale для чисел), nullable (может ли быть NULL в БД), unique (уникальность). Если не ставить @Column, ORM сам выберет имя колонки по имени поля и тип по типу поля. Эта аннотация нужна, когда требуется тонкая настройка (например, @Column(name="user_email", unique=true, nullable=false)).
@Version – отмечает поле, используемое для оптимистической блокировки (optimistic locking). Каждое изменение записи будет увеличивать версию. При обновлении Hibernate сравнит старую версию и новую; если кто-то другой изменил запись и версия уже не совпадает, будет выброшено исключение OptimisticLockException. Обычно используется тип int/long или java.sql.Timestamp.
@Embeddable / @Embedded – позволяют внедрять класс в состав сущности. @Embeddable ставится на класс- встроимый компонент (не отдельная сущность, а скорее группа колонок). @Embedded – на поле в сущности, указывая, что поля этого компонента должны храниться как колонки родительской таблицы. Например, класс Address с полями street, city можно объявить @Embeddable, а в User сделать @Embedded Address address – тогда таблица USER будет содержать колонки для street, city с префиксом или как настроено.
@MappedSuperclass – помечает класс, свойства которого наследуются сущностями, но сам класс не является сущностью таблицей. Это способ вынести общие поля (например, id, timestamps) в базовый класс. Класс с @MappedSuperclass не будет иметь собственной таблицы, но поля его будут включены в таблицы дочерних @Entity классов.
Пояснение
Эти аннотации – фундамент работы JPA:
Каждый класс-сущность обязан иметь @Entity. Без этого Hibernate (или другой ORM) не будет его воспринимать какpersistable. Аннотация @Table не обязательна, если имя таблицы совпадает с именем класса (с некоторыми конвенциями). Однако, на практике её указывают явно для ясности и чтобы задать имя точно (особенно если naming strategy в Hibernate меняет имена – например, User -> USER или user).
Аннотации @Id и @GeneratedValue: первичный ключ может генерироваться базой (IDENTITY автоинкремент) или отдельной последовательностью. Например, для PostgreSQL часто делают @GeneratedValue(strategy = GenerationType.IDENTITY) на поле id serial. Для Oracle нужно либо @SequenceGenerator + SEQUENCE, либо теперь можно просто strategy = SEQUENCE и @SequenceGenerator(name="name", sequenceName="SEQ_NAME"). Опция AUTO даёт Hibernate сам решить: он может создать специальную таблицу SEQUENCE (на некоторых БД, где нет native sequences).
@Column стоит указывать, когда название поля не подходит для колонки (например, поле lastName может автоматически отобразиться как LAST_NAME или LASTNAME в зависимости от настроек; если хотим определённо last_name – прописываем). Также, по умолчанию строки VARCHAR(255), если нужно больше – @Column(length=500) например. У чисел precision и scale актуальны для BigDecimal (например, денежные суммы: precision=12, scale=2 – всего 12 цифр, 2 из них после запятой).
@Version – реализация оптимистической блокировки полезна в конкурентной среде. Например, два пользователя читают одну запись, оба вносят изменения. У записи версия 1. Первый сохранил – запись обновилась, версия стала 2. Второй пытается сохранить свои изменения тоже исходя из версии 1, Hibernate увидит mismatch (в базе версия 2, а у второго пользователя объект с версией 1) – и бросит исключение о конфликте. Можно отловить и сообщить пользователю, что данные устарели. Это чаще всего легче, чем пессимистическая блокировка (SELECT ... FOR UPDATE).
@Embeddable/@Embedded помогают избежать дублирования колонок. Вместо копирования полей адреса в каждую сущность (User, Company, etc.), определяем класс Address и используем его. Hibernate "развернёт" embedded-объект в те же колонки таблицы. Можно даже вложенные Embedded делать. Без этой возможности пришлось бы привязывать адрес через отдельную таблицу Address и связь, но если смысл выделять таблицу нет, embedded – хорошее решение.
@MappedSuperclass – тоже про избавление от дублирования, но на уровне кода: базовый класс, например BaseEntity с полем id, или AuditFields с полями createdAt, updatedAt. Сущности наследуют, и Hibernate добавляет эти поля в их таблицы. В отличие от @Entity-наследования, @MappedSuperclass не требует стратегий наследования и не создает отдельную таблицу под базовый класс.
