在 Spring Data JPA 中,实现复杂查询可以通过多种方式,下面将详细介绍几种常见的方法并给出示例。

1. 使用方法命名规则

Spring Data JPA 允许你根据方法名自动创建查询。当你定义一个符合特定命名规则的方法时,Spring Data JPA 会自动解析方法名并生成相应的 SQL 查询。

示例

假设我们有一个 User 实体类:

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private int age;

    // 构造函数、getter 和 setter 方法
    public User() {}

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

然后创建一个 UserRepository 接口:

import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;

public interface UserRepository extends JpaRepository<User, Long> {
    // 查询年龄大于指定值的用户
    List<User> findByAgeGreaterThan(int age);

    // 查询姓名包含指定字符串且年龄小于指定值的用户
    List<User> findByNameContainingAndAgeLessThan(String name, int age);
}

在服务层使用该方法:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    public List<User> getUsersByAgeGreaterThan(int age) {
        return userRepository.findByAgeGreaterThan(age);
    }

    public List<User> getUsersByNameContainingAndAgeLessThan(String name, int age) {
        return userRepository.findByNameContainingAndAgeLessThan(name, age);
    }
}

2. 使用 @Query 注解

@Query 注解允许你直接在方法上定义 JPQL(Java Persistence Query Language)或 SQL 查询。

示例

修改 UserRepository 接口:

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;

public interface UserRepository extends JpaRepository<User, Long> {
    // 使用 JPQL 查询年龄在指定范围内的用户
    @Query("SELECT u FROM User u WHERE u.age BETWEEN :minAge AND :maxAge")
    List<User> findUsersByAgeRange(int minAge, int maxAge);

    // 使用原生 SQL 查询姓名以指定字符串开头的用户
    @Query(value = "SELECT * FROM user WHERE name LIKE :prefix%", nativeQuery = true)
    List<User> findUsersByNamePrefix(String prefix);
}

在服务层使用这些方法:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    public List<User> getUsersByAgeRange(int minAge, int maxAge) {
        return userRepository.findUsersByAgeRange(minAge, maxAge);
    }

    public List<User> getUsersByNamePrefix(String prefix) {
        return userRepository.findUsersByNamePrefix(prefix);
    }
}

3. 使用 Specification 接口

Specification 接口用于动态构建查询条件,适用于需要根据不同条件组合查询的场景。

示例

首先创建一个 UserSpecification 类:

import org.springframework.data.jpa.domain.Specification;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

public class UserSpecification {
    public static Specification<User> hasName(String name) {
        return (Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) ->
                cb.like(root.get("name"), "%" + name + "%");
    }

    public static Specification<User> hasAgeGreaterThan(int age) {
        return (Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) ->
                cb.gt(root.get("age"), age);
    }
}

然后在服务层使用 Specification

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    public List<User> getUsersBySpecification(String name, int age) {
        Specification<User> spec = Specification.where(UserSpecification.hasName(name))
                .and(UserSpecification.hasAgeGreaterThan(age));
        return userRepository.findAll(spec);
    }
}

通过以上几种方法,你可以在 Spring Data JPA 中实现复杂查询。根据具体的业务需求,选择合适的方法来构建查询。