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

Какие знаешь стратегии наследования в JPA?

2.0 Middle🔥 71 комментариев
#ORM и Hibernate

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

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

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

Стратегии наследования в JPA

Наследование в JPA — это механизм маппирования иерархии классов Java на таблицы в базе данных. JPA предоставляет три основные стратегии.

1. SINGLE_TABLE (Одна таблица)

Все классы иерархии хранятся в одной таблице с дополнительной колонкой дискриминатор (discriminator) для определения типа.

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "employee_type", discriminatorType = DiscriminatorType.STRING)
public abstract class Employee {
    @Id
    private Long id;
    private String name;
}

@Entity
@DiscriminatorValue("MANAGER")
public class Manager extends Employee {
    private String department;
}

@Entity
@DiscriminatorValue("DEVELOPER")
public class Developer extends Employee {
    private String programmingLanguage;
}

Таблица в БД:

employee
├─ id
├─ name
├─ employee_type (MANAGER / DEVELOPER)
├─ department (NULL для Developer)
└─ programming_language (NULL для Manager)

Плюсы: быстрые запросы, простая логика, хорошо для небольших иерархий Минусы: много NULL колонок, нарушение нормализации БД

2. TABLE_PER_CLASS (Таблица для каждого класса)

Каждый класс (включая parent) имеет свою таблицу со всеми своими колонками.

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Employee {
    @Id
    private Long id;
    private String name;
}

@Entity
public class Manager extends Employee {
    private String department;
}

@Entity
public class Developer extends Employee {
    private String programmingLanguage;
}

Таблицы в БД:

manager
├─ id
├─ name
└─ department

developer
├─ id
├─ name
└─ programming_language

Плюсы: нормализованная БД, нет NULL колонок, каждая таблица компактна Минусы: запросы к parent типу требуют UNION (медленнее), полиморфные запросы сложные

3. JOINED (Объединённые таблицы)

Паrent класс в отдельной таблице, каждый child класс добавляет свою таблицу с внешним ключом на parent.

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Employee {
    @Id
    private Long id;
    private String name;
}

@Entity
@PrimaryKeyJoinColumn(name = "employee_id")
public class Manager extends Employee {
    private String department;
}

@Entity
@PrimaryKeyJoinColumn(name = "employee_id")
public class Developer extends Employee {
    private String programmingLanguage;
}

Таблицы в БД:

employee
├─ id (PRIMARY KEY)
└─ name

manager
├─ employee_id (FK -> employee.id)
└─ department

developer
├─ employee_id (FK -> employee.id)
└─ programming_language

Плюсы: нормализованная БД, нет NULL, логичная структура, полиморфные запросы работают Минусы: JOIN операции при загрузке child, медленнее чем SINGLE_TABLE для простых запросов

Сравнительная таблица

КритерийSINGLE_TABLETABLE_PER_CLASSJOINED
ПроизводительностьОчень быстроМедленно (UNION)Хорошо
НормализацияПлохаяХорошаяХорошая
NULL колонкиМногоНетНет
Запросы по parentБыстроМедленноБыстро
Размер таблицБольшиеМаленькиеСреднее

Рекомендации по использованию

  • SINGLE_TABLE — для небольших иерархий, когда нужна максимальная производительность
  • JOINED — оптимальный баланс (default для JPA), используется чаще всего
  • TABLE_PER_CLASS — редко, когда классы совсем разные и разных таблицы логичнее