Какие типы данных можно использовать в качестве первичного ключа (ID) в JPA/Hibernate?

«Какие типы данных можно использовать в качестве первичного ключа (ID) в JPA/Hibernate?» — вопрос из категории Hibernate, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В JPA/Hibernate для поля, помеченного @Id, можно использовать различные типы данных, соответствующие критериям хорошего первичного ключа: уникальность, неизменность, простота и эффективность для индексирования.

Основные варианты:

  1. Числовые типы (Long, Integer): Самый распространённый выбор. Часто используются в связке с автоинкрементом в БД.

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // Для MySQL, PostgreSQL
    private Long id;
  2. UUID (java.util.UUID): Идеален для распределённых систем, где генерация ID происходит на стороне приложения. Гарантирует глобальную уникальность.

    @Id
    @GeneratedValue(generator = "UUID")
    @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
    private UUID id;
    // Или с Java 8+
    @Id
    @GeneratedValue
    private UUID id; // Hibernate 5+ может генерировать сам
  3. Строковый тип (String): Подходит для естественных ключей (например, код товара, ISBN), но не для автоинкремента. Требует ручной установки значения.

    @Id
    private String isbn; // Пример естественного ключа
  4. Составной ключ (Composite Key): Используется класс, помеченный @Embeddable, и поле сущности с @EmbeddedId, когда уникальность определяется комбинацией нескольких полей.

    @Embeddable
    public class AccountId implements Serializable {
        private String accountNumber;
        private String accountType;
        // equals(), hashCode()
    }
    
    @Entity
    public class Account {
        @EmbeddedId
        private AccountId id;
        // ...
    }
  5. Другие типы: Любой тип, реализующий интерфейс Serializable и корректные методы equals() и hashCode(), например, BigInteger или пользовательский тип.

Рекомендация: Для большинства случаев предпочтительны Long (с автоинкрементом) или UUID (для распределённых систем).