Ответ
Нативные SQL-запросы используются, когда возможности ORM (например, Hibernate) или JPA Criteria API недостаточны для сложных операций, требующих максимальной производительности или специфичного синтаксиса СУБД.
Основные сценарии использования:
- Сложные аналитические запросы: Оконные функции (
OVER,PARTITION BY), рекурсивные CTE. - Массовые операции (Batch Update):
UPDATE ... WHERE ...для тысяч строк, что эффективнее поэтапного сохранения сущностей. - Специфичные оптимизации: Использование подсказок для оптимизатора (
/*+ INDEX(...) */в Oracle),FOR UPDATE SKIP LOCKED.
Примеры выполнения:
1. Через JPA EntityManager (с маппингом на сущность):
@PersistenceContext
private EntityManager em;
public List<User> findActiveUsersNative() {
String sql = "SELECT * FROM app_user WHERE is_active = true";
Query query = em.createNativeQuery(sql, User.class); // User должен быть @Entity
return query.getResultList();
}
2. Через Spring JdbcTemplate (для проекций или DTO):
@Autowired
private JdbcTemplate jdbcTemplate;
public List<UserStatsDto> getUserStatistics() {
String sql = """
SELECT department_id,
COUNT(*) as user_count,
AVG(salary) as avg_salary
FROM employee
GROUP BY department_id
""";
return jdbcTemplate.query(sql, (rs, rowNum) ->
new UserStatsDto(
rs.getLong("department_id"),
rs.getInt("user_count"),
rs.getBigDecimal("avg_salary")
)
);
}
Критически важные правила:
- Всегда используйте параметризацию (
?или:name) для предотвращения SQL-инъекций. Никогда не конкатенируйте пользовательский ввод в строку запроса. - Помните о переносимости: Нативный запрос, использующий специфичный для PostgreSQL синтаксис (например,
ILIKE), не будет работать на MySQL. - Учитывайте кэш второго уровня Hibernate: Результаты нативных запросов могут не обновлять кэш сущностей, что приводит к несогласованности данных.