← Назад к вопросам
Какой метод будем использовать для поиска в Repository?
1.0 Junior🔥 161 комментариев
#Spring Boot и Spring Data
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Методы поиска в Spring Data Repository
Это вопрос о практическом использовании Spring Data JPA для работы с данными. Давайте разберёмся в различных способах поиска в репозитории.
Основные методы Repository
1. Встроенные методы интерфейса CrudRepository
public interface CrudRepository<T, ID> extends Repository<T, ID> {
// Поиск по ID
Optional<T> findById(ID id);
// Получить все
Iterable<T> findAll();
// С пагинацией
Page<T> findAll(Pageable pageable);
// Сохранение
<S extends T> S save(S entity);
// Удаление
void deleteById(ID id);
}
Пример использования:
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// Унаследованные методы
}
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public User getUserById(Long id) {
// findById возвращает Optional
return userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException(id));
}
public List<User> getAllUsers() {
return (List<User>) userRepository.findAll();
}
public Page<User> getUsersPaginated(int page, int size) {
Pageable pageable = PageRequest.of(page, size);
return userRepository.findAll(pageable);
}
}
**2. Query Methods (Производные запросы)
Spring Data генерирует SQL на основе имени метода:
public interface UserRepository extends JpaRepository<User, Long> {
// Простой поиск по одному полю
User findByEmail(String email);
// Поиск с Optional
Optional<User> findByEmail(String email);
// Поиск со списком результатов
List<User> findByStatus(String status);
// Диапазонный поиск
List<User> findByAgeBetween(int minAge, int maxAge);
// Поиск по нескольким условиям
List<User> findByFirstNameAndLastName(String firstName, String lastName);
// Логический оператор OR
List<User> findByFirstNameOrEmail(String firstName, String email);
// Сравнение
List<User> findByAgeGreaterThan(int age);
List<User> findByAgeGreaterThanEqual(int age);
List<User> findByAgeLessThan(int age);
// LIKE поиск
List<User> findByEmailContaining(String substring);
List<User> findByEmailStartingWith(String prefix);
List<User> findByEmailEndingWith(String suffix);
// Is NULL
List<User> findByEmailIsNull();
List<User> findByEmailIsNotNull();
// Сортировка
List<User> findByStatusOrderByCreatedAtDesc(String status);
List<User> findByStatus(String status, Sort sort);
// С пагинацией
Page<User> findByStatus(String status, Pageable pageable);
}
Синтаксис Query Methods:
find + (By | Distinct) + [Entity]By + Criteria + [OrderBy] + [Asc | Desc]
Примеры сложных методов:
public interface UserRepository extends JpaRepository<User, Long> {
// Поиск с сортировкой
List<User> findByAgeGreaterThan(int age, Sort sort);
// Использование
List<User> users = userRepository.findByAgeGreaterThan(25,
Sort.by("createdAt").descending()
);
// С пагинацией
Page<User> findByStatus(String status, Pageable pageable);
// Использование
Page<User> users = userRepository.findByStatus("ACTIVE",
PageRequest.of(0, 20, Sort.by("email").ascending())
);
}
3. @Query аннотация (JPQL)
Для сложных запросов используй явную JPQL:
public interface UserRepository extends JpaRepository<User, Long> {
// JPQL (Object-Oriented)
@Query("SELECT u FROM User u WHERE u.email = :email")
Optional<User> findByEmailJPQL(@Param("email") String email);
// С условиями
@Query("SELECT u FROM User u WHERE u.age > :age AND u.status = :status")
List<User> findActiveUsersOlderThan(
@Param("age") int age,
@Param("status") String status
);
// Со счётом
@Query("SELECT COUNT(u) FROM User u WHERE u.status = :status")
int countByStatus(@Param("status") String status);
// С JOIN
@Query("SELECT u FROM User u JOIN u.orders o WHERE o.totalPrice > :minPrice")
List<User> findUsersByMinOrderPrice(@Param("minPrice") BigDecimal minPrice);
// С GROUP BY
@Query("SELECT u.status, COUNT(u) FROM User u GROUP BY u.status")
List<Object[]> countByStatus();
}
4. @Query с Native SQL
Для database-specific SQL:
public interface UserRepository extends JpaRepository<User, Long> {
@Query(value = "SELECT * FROM users WHERE email = :email", nativeQuery = true)
Optional<User> findByEmailSQL(@Param("email") String email);
@Query(value = """
SELECT u.id, u.email, COUNT(o.id) as order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.status = :status
GROUP BY u.id, u.email
HAVING COUNT(o.id) > :minOrders
""", nativeQuery = true)
List<Object[]> findUsersWithOrderStats(
@Param("status") String status,
@Param("minOrders") int minOrders
);
}
5. Specification API (для динамических запросов)
Если нужны динамические критерии:
public interface UserRepository extends JpaRepository<User, Long>,
JpaSpecificationExecutor<User> {
}
public class UserSpecifications {
public static Specification<User> hasEmail(String email) {
return (root, query, cb) -> cb.equal(root.get("email"), email);
}
public static Specification<User> ageGreaterThan(int age) {
return (root, query, cb) -> cb.greaterThan(root.get("age"), age);
}
public static Specification<User> hasStatus(String status) {
return (root, query, cb) -> cb.equal(root.get("status"), status);
}
}
// Использование
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public List<User> searchUsers(String email, int minAge, String status) {
Specification<User> spec = Specification.where(null);
if (email != null) {
spec = spec.and(UserSpecifications.hasEmail(email));
}
if (minAge > 0) {
spec = spec.and(UserSpecifications.ageGreaterThan(minAge));
}
if (status != null) {
spec = spec.and(UserSpecifications.hasStatus(status));
}
return userRepository.findAll(spec);
}
}
Сравнение методов
| Метод | Сложность | Производительность | Гибкость | Использование |
|---|---|---|---|---|
| Query Methods | Простая | Хорошо | Средняя | Простые поиски |
| @Query JPQL | Средняя | Хорошо | Высокая | Сложные запросы |
| @Query SQL | Высокая | Отличная | Максимальная | DB-specific |
| Specification | Средняя | Хорошо | Максимальная | Динамические критерии |
| Example/ExampleMatcher | Простая | Среднее | Средняя | Поиск по примеру |
Практический пример: Полнотекстовый поиск
public interface ArticleRepository extends JpaRepository<Article, Long> {
// Просто
List<Article> findByTitleContaining(String keyword);
// Сложнее (с рейтингом)
@Query("""
SELECT a FROM Article a
WHERE a.title ILIKE CONCAT('%', :keyword, '%')
OR a.content ILIKE CONCAT('%', :keyword, '%')
ORDER BY CASE
WHEN a.title ILIKE CONCAT('%', :keyword, '%') THEN 1
ELSE 2
END
""")
List<Article> searchArticles(@Param("keyword") String keyword);
}
@Service
public class ArticleService {
@Autowired
private ArticleRepository articleRepository;
public List<Article> search(String keyword, Pageable pageable) {
// Для простого случая
return articleRepository.findByTitleContaining(keyword);
// Для сложного — используй нативный SQL
}
}
Рекомендации
- Query Methods: Для простых поисков (до 3 условий)
- @Query JPQL: Для сложных запросов с JOINs, GROUP BY
- @Query Native SQL: Когда нужна специфика БД
- Specification API: Для динамических критериев поиска
- Всегда используй Optional: Для методов, возвращающих одиночные результаты
- Используй Page: Для пагинации больших результатов
- Создавай индексы: На полях, по которым часто ищешь