Какие знаешь стратегии наследования в JPA?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Стратегии наследования в 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_TABLE | TABLE_PER_CLASS | JOINED |
|---|---|---|---|
| Производительность | Очень быстро | Медленно (UNION) | Хорошо |
| Нормализация | Плохая | Хорошая | Хорошая |
| NULL колонки | Много | Нет | Нет |
| Запросы по parent | Быстро | Медленно | Быстро |
| Размер таблиц | Большие | Маленькие | Среднее |
Рекомендации по использованию
- SINGLE_TABLE — для небольших иерархий, когда нужна максимальная производительность
- JOINED — оптимальный баланс (default для JPA), используется чаще всего
- TABLE_PER_CLASS — редко, когда классы совсем разные и разных таблицы логичнее