Какую стратегию генерации ID (@GeneratedValue) рекомендуется использовать в Hibernate?

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

Ответ

Рекомендация зависит от используемой СУБД и сценариев работы.

Оптимальные стратегии:

  1. GenerationType.IDENTITY

    • Для: MySQL, PostgreSQL, SQL Server, H2.
    • Как работает: Полагается на автоинкрементное поле базы данных. Hibernate выполняет вставку, чтобы получить сгенерированный ID.
      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      private Long id;
    • Недостаток: Может создавать узкое место при batch-вставках, так как ID запрашиваются по одному.
  2. GenerationType.SEQUENCE + оптимизированный генератор

    • Для: Oracle, PostgreSQL. Также предпочтительнее IDENTITY для batch-операций в поддерживаемых БД.
    • Как работает: Использует объект последовательности БД. Кэширование значений на стороне приложения значительно ускоряет вставку.
      @Id
      @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_gen")
      @SequenceGenerator(name = "seq_gen", sequenceName = "my_seq",
                     allocationSize = 50) // Кэширует 50 ID за раз
      private Long id;
    • Преимущество: Наилучшая производительность для массовых вставок.

Стратегии, которых следует избегать:

  • GenerationType.AUTO: Позволяет Hibernate выбрать стратегию, что может привести к неоптимальному или непереносимому выбору (например, созданию таблицы для генерации в некоторых конфигурациях).
  • GenerationType.TABLE: Использует отдельную таблицу-счетчик, что создает contention и является самым медленным вариантом.

Альтернатива для распределенных систем: Использование UUID (тип java.util.UUID с аннотацией @GeneratedValue или генерацией в коде).