← Назад к вопросам
Какие знаешь способы получить список людей по их имени в Spring Data JPA?
1.3 Junior🔥 261 комментариев
#Spring Boot и Spring Data
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Как получить список людей по имени в Spring Data JPA
Способ 1: Query Method (рекомендуется)
Это самый простой и элегантный способ — Spring Data автоматически генерирует SQL запрос из имени метода:
@Repository
public interface PersonRepository extends JpaRepository<Person, Long> {
// Точное совпадение
List<Person> findByName(String name);
// Игнорирование case
List<Person> findByNameIgnoreCase(String name);
// Частичное совпадение (содержит)
List<Person> findByNameContaining(String name);
// Case-insensitive содержит
List<Person> findByNameContainingIgnoreCase(String name);
// Начинается с
List<Person> findByNameStartingWith(String name);
// Заканчивается
List<Person> findByNameEndingWith(String name);
}
// Использование
@Service
public class PersonService {
@Autowired
private PersonRepository repository;
public List<Person> findPeople(String name) {
// Метод 1: точное совпадение
return repository.findByName("John");
// Метод 2: игнорировать case
return repository.findByNameIgnoreCase("john");
// Метод 3: содержит (для поиска по подстроке)
return repository.findByNameContainingIgnoreCase("oh"); // Найдёт John, Johnny
// Метод 4: начинается с
return repository.findByNameStartingWith("Jo"); // Найдёт John, Johnny
}
}
Способ 2: @Query с JPQL
Для более сложных запросов используй собственный JPQL:
@Repository
public interface PersonRepository extends JpaRepository<Person, Long> {
// Простой JPQL запрос
@Query("SELECT p FROM Person p WHERE p.name = :name")
List<Person> findByNameJpql(@Param("name") String name);
// Case-insensitive поиск
@Query("SELECT p FROM Person p WHERE LOWER(p.name) LIKE LOWER(CONCAT(%, :name, %))")
List<Person> findByNameContainingJpql(@Param("name") String name);
// Множественные условия
@Query("SELECT p FROM Person p WHERE p.name LIKE %:name% AND p.age > :minAge")
List<Person> findByNameAndAge(
@Param("name") String name,
@Param("minAge") int minAge
);
// С сортировкой
@Query("SELECT p FROM Person p WHERE p.name LIKE %:name% ORDER BY p.name")
List<Person> findByNameOrdered(@Param("name") String name);
}
Способ 3: Native SQL Query
Для специфичных БД-запросов или оптимизации производительности:
@Repository
public interface PersonRepository extends JpaRepository<Person, Long> {
// PostgreSQL с ILIKE (case-insensitive)
@Query(
value = "SELECT * FROM persons WHERE name ILIKE :name",
nativeQuery = true
)
List<Person> findByNameNativePostgres(@Param("name") String name);
// MySQL с LIKE
@Query(
value = "SELECT * FROM persons WHERE LOWER(name) LIKE LOWER(CONCAT(%, :name, %))",
nativeQuery = true
)
List<Person> findByNameNativeMysql(@Param("name") String name);
// С full-text search (если индекс есть)
@Query(
value = "SELECT * FROM persons WHERE MATCH(name) AGAINST(:name IN BOOLEAN MODE)",
nativeQuery = true
)
List<Person> findByNameFullText(@Param("name") String name);
}
Способ 4: Specification (для динамических запросов)
Когда параметры поиска неизвестны заранее:
// Спецификация для Person
public class PersonSpecification {
public static Specification<Person> nameContains(String name) {
return (root, query, cb) -> {
if (name == null || name.isEmpty()) {
return cb.conjunction(); // Нет фильтра
}
// Case-insensitive LIKE
return cb.like(
cb.lower(root.get("name")),
"%" + name.toLowerCase() + "%"
);
};
}
public static Specification<Person> nameExact(String name) {
return (root, query, cb) -> {
if (name == null || name.isEmpty()) {
return cb.conjunction();
}
return cb.equal(cb.lower(root.get("name")), name.toLowerCase());
};
}
public static Specification<Person> nameStartsWith(String name) {
return (root, query, cb) -> {
if (name == null || name.isEmpty()) {
return cb.conjunction();
}
return cb.like(
cb.lower(root.get("name")),
name.toLowerCase() + "%"
);
};
}
}
// Repository с Specification поддержкой
@Repository
public interface PersonRepository extends JpaRepository<Person, Long>,
JpaSpecificationExecutor<Person> {
}
// Использование
@Service
public class PersonService {
@Autowired
private PersonRepository repository;
public List<Person> search(String name, int minAge) {
Specification<Person> spec = PersonSpecification.nameContains(name)
.and((root, query, cb) -> cb.greaterThan(root.get("age"), minAge));
return repository.findAll(spec);
}
public Page<Person> searchPaginated(String name, Pageable pageable) {
Specification<Person> spec = PersonSpecification.nameContains(name);
return repository.findAll(spec, pageable);
}
}
Способ 5: QueryDSL (для типобезопасных запросов)
Для большей безопасности типов:
// Зависимость в pom.xml
// <dependency>
// <groupId>com.querydsl</groupId>
// <artifactId>querydsl-jpa-codegen</artifactId>
// </dependency>
@Repository
public interface PersonRepository extends JpaRepository<Person, Long>,
QuerydslPredicateExecutor<Person> {
}
// Использование
@Service
public class PersonService {
@Autowired
private PersonRepository repository;
public List<Person> findByName(String name) {
QPerson qPerson = QPerson.person;
return repository.findAll(
qPerson.name.containsIgnoreCase(name)
);
}
public List<Person> findByMultipleCriteria(String name, int minAge) {
QPerson qPerson = QPerson.person;
Predicate predicate = qPerson.name.containsIgnoreCase(name)
.and(qPerson.age.goe(minAge)); // goe = greater or equal
return repository.findAll(predicate);
}
}
Способ 6: EntityManager (для полного контроля)
Когда нужна максимальная гибкость:
@Service
public class PersonService {
@Autowired
private EntityManager entityManager;
public List<Person> findByName(String name) {
String jpql = "SELECT p FROM Person p WHERE LOWER(p.name) LIKE LOWER(:name)";
return entityManager.createQuery(jpql, Person.class)
.setParameter("name", "%" + name + "%")
.getResultList();
}
public List<Person> findByNameWithPagination(String name, int page, int size) {
String jpql = "SELECT p FROM Person p WHERE LOWER(p.name) LIKE LOWER(:name) ORDER BY p.name";
return entityManager.createQuery(jpql, Person.class)
.setParameter("name", "%" + name + "%")
.setFirstResult((page - 1) * size) // Offset
.setMaxResults(size) // Limit
.getResultList();
}
public long countByName(String name) {
String jpql = "SELECT COUNT(p) FROM Person p WHERE LOWER(p.name) LIKE LOWER(:name)";
return entityManager.createQuery(jpql, Long.class)
.setParameter("name", "%" + name + "%")
.getSingleResult();
}
}
Практический пример: полнофункциональный поиск
@Repository
public interface PersonRepository extends JpaRepository<Person, Long>,
JpaSpecificationExecutor<Person> {
// Быстрые методы
List<Person> findByNameIgnoreCase(String name);
List<Person> findByNameContainingIgnoreCase(String name);
}
@Service
public class PersonService {
@Autowired
private PersonRepository repository;
// Способ 1: просто по имени
public List<Person> findExactName(String name) {
return repository.findByNameIgnoreCase(name);
}
// Способ 2: поиск по подстроке
public List<Person> findBySubstring(String name) {
return repository.findByNameContainingIgnoreCase(name);
}
// Способ 3: сложный поиск с пагинацией
public Page<Person> advancedSearch(String name, int age, Pageable pageable) {
Specification<Person> spec = (root, query, cb) -> {
List<javax.persistence.criteria.Predicate> predicates = new ArrayList<>();
if (name != null && !name.isEmpty()) {
predicates.add(
cb.like(cb.lower(root.get("name")), "%" + name.toLowerCase() + "%")
);
}
if (age > 0) {
predicates.add(cb.greaterThan(root.get("age"), age));
}
return cb.and(predicates.toArray(new javax.persistence.criteria.Predicate[0]));
};
return repository.findAll(spec, pageable);
}
// REST endpoint
@GetMapping("/search")
public Page<Person> search(
@RequestParam(required = false) String name,
@RequestParam(required = false, defaultValue = "0") int age,
@PageableDefault(size = 20, sort = "name") Pageable pageable
) {
return advancedSearch(name, age, pageable);
}
}
Сравнение всех способов
| Способ | Простота | Гибкость | Производительность | Когда использовать |
|---|---|---|---|---|
| Query Method | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 80% случаев |
| @Query JPQL | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | Сложные запросы |
| Native SQL | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | БД-специфичные |
| Specification | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | Динамические |
| QueryDSL | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | Типобезопасность |
| EntityManager | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | Полный контроль |
Рекомендуемый подход
// Сначала используй Query Method
List<Person> findByNameContainingIgnoreCase(String name);
// Если нужна пагинация
Page<Person> findByNameContainingIgnoreCase(String name, Pageable pageable);
// Если много условий — используй Specification
// Если нужна абсолютная производительность — используй native SQL
Best practice: начни с Query Method, переходи на Specification если условия усложняются, и только потом на Native SQL для оптимизации.