middle
Что такое проекции и DTO-маппинг?
Проекции позволяют загружать только нужные поля из БД, а не полные сущности. Это оптимизирует производительность и решает проблемы с LAZY-загрузкой и безопасностью (не отдавать лишние данные).
DTO через JPQL-конструктор
Пример
public record UserDto(String name, String email) {}
@Query("SELECT new com.example.UserDto(u.name, u.email) FROM User u WHERE u.id = :id")
Optional<UserDto> findUserDtoById(@Param("id") Long id);
// SQL: SELECT u.name, u.email FROM users u WHERE u.id = ?
Interface-based проекция (Spring Data)
Пример
public interface UserSummary {
String getName();
String getEmail();
@Value("#{target.name + ' <' + target.email + '>'}")
String getDisplayName(); // вычисляемое поле (SpEL)
}
public interface UserRepository extends JpaRepository<User, Long> {
List<UserSummary> findByStatus(UserStatus status);
// Spring Data автоматически загружает только name и email
}
Class-based проекция (DTO класс)
Пример
public record UserDto(String name, String email) {}
List<UserDto> findByStatus(UserStatus status);
// Spring Data маппит результат в DTO автоматически (по именам полей)
Tuple (кортеж) — для ad-hoc запросов
Пример
List<Tuple> results = entityManager.createQuery(
"SELECT u.name AS name, COUNT(o) AS orderCount " +
"FROM User u LEFT JOIN u.orders o GROUP BY u.name", Tuple.class)
.getResultList();
results.forEach(t -> System.out.println(
t.get("name") + ": " + t.get("orderCount")));
Важное
- Проекции загружают только нужные столбцы → меньше трафика, памяти, нет LAZY-проблем
- Interface-based проекции — удобны, но создают прокси (чуть медленнее)
- Record DTO — оптимальный по производительности вариант
- Проекции не отслеживаются Persistence Context → нет Dirty Checking
Частые ошибки
- Загружать полную Entity для read-only отображения — лишний overhead: Dirty Checking, snapshot, L1 Cache
- Смешивать проекции и Entity — проекция возвращает DTO, не managed Entity; изменения в DTO не попадут в БД
- Сложные SpEL в interface-проекциях — сложнее для отладки и тестирования
Как используется в 2026
- DTO-проекции — стандарт для REST API (разделение read/write модели — CQRS-lite)
- Java Records идеально подходят для DTO — иммутабельные, компактные
- Spring Data автоматически оптимизирует SELECT при использовании interface/class проекций
На собеседовании: проекции — это способ загружать только нужные поля вместо полной Entity. Назовите три вида: JPQL-конструктор, interface-based, class-based (record). Объясните, почему проекции лучше для REST API: нет Dirty Checking overhead, нет LAZY-проблем, не отдаём лишние данные клиенту.