SQL-запросы и Hibernate

Выбор не бинарный: одно приложение может использовать сущности для изменения агрегатов, DTO-проекции для чтения и JDBC для массовых операций.

КритерийHibernate/JPAЯвный SQL
CRUD и граф сущностейменьше служебного кодамаппинг пишется вручную
сложный отчётJPQL может мешатьдоступны все возможности СУБД
массовый updateконтекст становится лишнимодна команда предсказуемее
переносимостьвыше в стандартном APIзапрос зависит от диалекта
контроль планакосвенныйSQL виден сразу
dirty checkingвстроенизменения задаются явно

Практическое правило

Использовать сущности, когда операция действительно меняет объектную модель и её инварианты. Использовать проекцию или SQL, когда нужен конкретный набор данных, а не управляемый граф.

Даже при Hibernate проверять:

  • количество SQL-команд;
  • фактический план выполнения;
  • индексы;
  • объём переданных строк;
  • влияние fetch join, сортировки и пагинации;
  • batch для вставок и обновлений.

Смешанный сценарий

Если внутри JPA-транзакции выполняется JDBC, перед чтением данных, изменённых ORM, может потребоваться flush. После SQL update уже managed-сущности следует очистить или перечитать, иначе они останутся устаревшими.

Типичные ошибки

  • сравнивать технологии по одному искусственному benchmark;
  • полагать, что короткий JPQL гарантирует дешёвый SQL;
  • загружать сущности для read-only отчёта;
  • выполнять тысячи save вместо batch;
  • строить SQL строковой конкатенацией вместо параметров.

Вопросы для повторения

  1. Когда SQL предпочтительнее ORM? Для сложной аналитики, массовых операций и случаев, где важен точный план.
  2. Можно ли использовать оба подхода в одной транзакции? Да, но нужно синхронизировать persistence context.
  3. Почему DTO дешевле сущности для чтения? Нет снимка dirty checking и лишнего графа.
  4. ORM делает запросы безопасными автоматически? Параметризованный JPQL — да для значений; динамическая конкатенация всё ещё опасна.

Связано: Hibernate, JDBC, Persistence Context, SQL оценка производительности.