← Назад к вопросам

Как напишешь 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();
    }
}

Лучшие практики

  1. Предпочитай JPQL перед native SQL - портативнее, безопаснее
  2. Используй параметры :param вместо конкатенации - защита от SQL injection
  3. Для простых запросов используй методы репозитория - Spring Data сам генерирует запрос
  4. Используй проекции для больших данных - избегай загрузки всей entity
  5. JOIN FETCH для оптимизации - избегай N+1 проблемы
  6. Параметризованные запросы обязательны - безопасность и производительность
Как напишешь SQL запрос для внедрения в Spring Data JPA | PrepBro