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

Какие знаешь способы получить список людей по их имени в 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 для оптимизации.

Какие знаешь способы получить список людей по их имени в Spring Data JPA? | PrepBro