← Назад к вопросам
Как напишешь SQL запрос для внедрения в Spring Data JPA
1.0 Junior🔥 241 комментариев
#Spring Boot и Spring Data#Базы данных и SQL
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# SQL запросы в Spring Data JPA
Основные подходы внедрения SQL запросов
Spring Data JPA предоставляет несколько способов для работы с кастомными SQL запросами, каждый имеет свои преимущества и область применения.
1. @Query с JPQL (рекомендуется)
Это наиболее портативный подход, работающий независимо от БД:
interface UserRepository extends JpaRepository<User, Long> {
@Query("SELECT u FROM User u WHERE u.email = :email AND u.active = true")
Optional<User> findActiveUserByEmail(@Param("email") String email);
@Query("SELECT new map(u.id as id, u.name as name, COUNT(p) as postCount) " +
"FROM User u LEFT JOIN u.posts p " +
"WHERE u.createdAt > :date " +
"GROUP BY u.id")
List<Map<String, Object>> getUsersWithPostCount(@Param("date") LocalDateTime date);
}
Преимущества:
- Независимость от конкретной БД
- Типобезопасность через Criteria API
- Легко читается и поддерживается
2. @Query с native SQL
Для сложных запросов, специфичных для PostgreSQL/MySQL:
interface UserRepository extends JpaRepository<User, Long> {
@Query(value = "SELECT * FROM users u WHERE u.email ILIKE :email",
nativeQuery = true)
List<User> findRecentUsersByEmail(@Param("email") String email);
}
Особенности:
nativeQuery = trueсообщает, что это SQL- Колонки маппятся по имени к полям entity
- Результаты приводятся к типу return'а
3. Использование @Modifying для INSERT/UPDATE/DELETE
interface UserRepository extends JpaRepository<User, Long> {
@Modifying
@Transactional
@Query("UPDATE User u SET u.status = :status WHERE u.lastLogin < :date")
int deactivateInactiveUsers(@Param("status") String status,
@Param("date") LocalDateTime date);
}
Важно:
@Modifyingуказывает на изменение данных@Transactionalобязателен (иначе исключение)- Возвращаемое значение - количество затронутых строк
4. Проекции (DTO pattern)
Для избежания загрузки всей entity:
public interface UserDTO {
Long getId();
String getName();
String getEmail();
}
interface UserRepository extends JpaRepository<User, Long> {
@Query("SELECT u.id, u.name, u.email FROM User u WHERE u.id = :id")
UserDTO findUserDTOById(@Param("id") Long id);
}
5. Criteria API (программный подход)
Для динамических запросов:
@Service
public class UserService {
@Autowired
private EntityManager em;
public List<User> searchUsers(String name) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
Root<User> user = query.from(User.class);
List<Predicate> predicates = new ArrayList<>();
if (name != null) {
predicates.add(cb.like(user.get("name"), "%" + name + "%"));
}
query.where(cb.and(predicates.toArray(new Predicate[0])));
return em.createQuery(query).getResultList();
}
}
Лучшие практики
- Предпочитай JPQL перед native SQL - портативнее, безопаснее
- Используй параметры
:paramвместо конкатенации - защита от SQL injection - Для простых запросов используй методы репозитория - Spring Data сам генерирует запрос
- Используй проекции для больших данных - избегай загрузки всей entity
- JOIN FETCH для оптимизации - избегай N+1 проблемы
- Параметризованные запросы обязательны - безопасность и производительность