JpaRepository @Query("") 模糊查询 判断参数是否为null或""
时间: 2023-07-19 14:07:46 浏览: 301
你可以使用JPQL中的COALESCE函数来实现。COALESCE函数接受多个参数,返回第一个非null参数的值。因此,你可以将模糊查询的参数与一个空字符串作为COALESCE函数的参数,当参数为null时,COALESCE函数会返回空字符串,从而避免了模糊查询时出现null参数的问题。
示例代码如下:
```java
@Query("SELECT e FROM Entity e WHERE e.name LIKE CONCAT('%', COALESCE(:name, ''), '%')")
List<Entity> findByName(@Param("name") String name);
```
在上面的示例中,COALESCE函数的第一个参数是模糊查询的参数name,第二个参数是空字符串。如果name为null,则COALESCE函数会返回空字符串,否则返回name的值。然后将COALESCE函数的返回值与通配符拼接起来,进行模糊查询。
相关问题
JpaRepository使用方法查询条件查询
<think>好的,用户现在想了解如何在JpaRepository中使用方法查询进行条件查询,特别是用法和示例。根据用户提供的引用内容,我需要结合之前的回答和引用中的信息来构建一个清晰的解答。首先,用户提到了几个引用,其中引用[2]、[3]、[4]和[5]都涉及到JpaRepository的条件查询方法。比如引用[4]中的UserRepository接口,展示了方法名查询的示例,如findByUserName、findByUserNameAndAge等。这说明用户可能已经了解到通过方法命名规则进行查询的方式,但需要更详细的解释和示例。接下来,我需要回顾之前的回答,用户之前的问题是关于JpaRepository的多表关联查询,现在转向了更基础的方法查询条件。这可能意味着用户对JpaRepository的使用还不够熟悉,需要从简单条件查询开始了解。用户的问题核心是方法查询的条件查询用法和示例,所以我需要分步骤解释JpaRepository支持的几种条件查询方式,包括方法名约定、@Query注解、Example查询等。同时,要结合引用中的示例代码,如引用[4]中的代码,展示具体的实现方法。需要注意用户可能存在的误区,比如方法名的拼写规则,参数顺序是否正确,以及如何处理更复杂的条件。例如,用户可能想知道如何实现模糊查询或者范围查询,这时候需要提供对应的示例,如findByNameLike或findByAgeBetween。此外,用户可能对动态条件查询感兴趣,比如如何根据不同的参数组合查询,这时候可以提到使用JPA Specification或者Querydsl,但根据用户的问题,可能更倾向于基本的方法名约定和@Query注解。需要确保回答结构清晰,分点说明每种方法,并给出代码示例。同时,引用相关的引用内容,如引用[2]中提到的JpaRepository支持接口规范方法名查询,引用[4]中的具体方法示例,来增强回答的可信度。
最后,生成的相关问题需要围绕方法查询的进一步应用,如动态排序、复杂条件组合等,帮助用户深入理解。</think>### JpaRepository 方法查询条件查询详解
#### 一、基于方法命名规则的查询(核心方法)
通过规范的方法命名自动生成查询逻辑[^2],适用于简单条件组合:
```java
public interface UserRepository extends JpaRepository<User, Integer> {
// 精确匹配(等于)
User findByUserName(String userName); // 等价 WHERE user_name = ? [^4]
// 多条件 AND 连接
List<User> findByUserNameAndAge(String userName, Integer age); // WHERE user_name=? AND age=?
// 模糊查询(LIKE)
List<User> findByUserNameLike(String pattern); // WHERE user_name LIKE ?
// 范围查询
List<User> findByAgeBetween(int min, int max); // WHERE age BETWEEN ? AND ?
// 空值判断
List<User> findByEmailIsNull();
// 排序控制
List<User> findByAgeGreaterThanOrderByCreateTimeDesc(int age); // WHERE age > ? ORDER BY create_time DESC
}
```
**关键命名规则**:
- `属性名`:必须与实体类字段名严格匹配(区分大小写)
- `条件关键词`:`And`/`Or`/`Between`/`LessThan`/`IsNull`等
- `排序控制`:`OrderBy[属性名][Asc/Desc]`
#### 二、@Query 注解自定义查询
当方法名过于复杂时,使用 JPQL 或原生 SQL 实现[^2]:
```java
// JPQL 查询(推荐)
@Query("SELECT u FROM User u WHERE u.age > :minAge AND u.createTime < :endDate")
List<User> findActiveUsers(@Param("minAge") int age, @Param("endDate") LocalDateTime date);
// 原生 SQL 查询(需严格匹配结果集)
@Query(value = "SELECT * FROM users WHERE DATEDIFF(NOW(), last_login) > 30",
nativeQuery = true)
List<User> findInactiveUsers();
```
**参数绑定方式**:
1. 位置参数:`?1`、`?2`(易出错,不推荐)
2. 命名参数:`:paramName` + `@Param`注解(推荐)
#### 三、动态条件查询(Example 查询)
适用于不确定查询条件的场景:
```java
// 创建 Example 模板
User probe = new User();
probe.setName("张%"); // 设置模糊查询条件
ExampleMatcher matcher = ExampleMatcher.matching()
.withMatcher("name", match -> match.startsWith()) // 姓名以"张"开头
.withIgnorePaths("age"); // 忽略age字段
List<User> results = userRepository.findAll(Example.of(probe, matcher));
```
**支持的匹配模式**:
- `exact`:精确匹配(默认)
- `contains`:包含模式(LIKE %value%)
- `start`/`ending`:开头/结尾匹配
#### 四、分页与排序组合查询
结合`Pageable`参数实现分页排序[^5]:
```java
// 创建分页请求(页码从0开始)
Pageable pageable = PageRequest.of(0, 10, Sort.by("createTime").descending());
// 方法名查询分页
Page<User> page1 = userRepository.findByAgeGreaterThan(18, pageable);
// @Query 分页查询
@Query("SELECT u FROM User u WHERE u.status = 1")
Page<User> findActiveUsers(Pageable pageable);
```
**返回类型选择**:
- `List<User>`:仅获取数据
- `Page<User>`:包含分页元数据(总页数、当前页码等)
- `Slice<User>`:轻量级分页(不计算总数)
#### 五、复合条件处理技巧
1. **Optional 处理空结果**:
```java
Optional<User> optionalUser = userRepository.findByEmail("[email protected]");
optionalUser.ifPresent(user -> System.out.println(user.getName()));
```
2. **流式处理结果集**:
```java
try (Stream<User> stream = userRepository.findAllByStatus("ACTIVE")) {
stream.filter(u -> u.getAge() > 30)
.forEach(System.out::println);
}
```
3. **修改查询(需加@Modifying)**:
```java
@Modifying
@Query("UPDATE User u SET u.loginCount = u.loginCount + 1 WHERE u.id = :userId")
int incrementLoginCount(@Param("userId") Long id);
```
---
### 最佳实践建议
1. **索引优化**:对`WHERE`条件中的高频查询字段添加`@Index`
```java
@Entity
@Table(indexes = @Index(name = "idx_user_name", columnList = "userName"))
public class User { /*...*/ }
```
2. **N+1 查询规避**:使用`@EntityGraph`预加载关联数据
```java
@EntityGraph(attributePaths = {"orders"})
List<User> findByCompanyId(Long companyId);
```
3. **查询结果缓存**:添加`@Cacheable`注解
```java
@Cacheable("users")
User findByEmployeeId(String empId);
```
---
public interface InviteCodeRepository extends JpaRepository<InviteCode, Integer> , JpaSpecificationExecutor<InviteCode> { /** * 分页获取InviteCode数据(按字段和值搜索) */ default Page<InviteCode> findPaginatedPAProductByAdminIdAndFieldAndValue(Integer adminId, String field, String value, Pageable pageable) { Specification<InviteCode> spec = (root, query, criteriaBuilder) -> { List<Predicate> predicates = new ArrayList<>(); // 添加 admin_id 的条件 predicates.add(criteriaBuilder.equal(root.get("admin_id"), adminId)); // 动态添加字段和值的条件 if (field != null && value != null) { // 修改为模糊查询 predicates.add(criteriaBuilder.like(root.get(field), "%" + value + "%")); } return criteriaBuilder.and(predicates.toArray(new Predicate[0])); }; return findAll(spec, pageable); }
<think>嗯,用户的问题是关于Spring Data JPA中如何实现自定义分页查询和动态模糊匹配的,特别是使用Specification的示例。我需要仔细分析他们的需求,并提供清晰的步骤和代码示例。
首先,用户提到了自定义分页查询和动态模糊匹配。根据之前的引用内容,Specification接口和JpaSpecificationExecutor是实现动态查询的关键。我需要先回顾一下相关的知识点,确保回答正确。
动态模糊匹配通常涉及到like查询,这在JPA中可以通过CriteriaBuilder的like方法来实现。而分页则需要使用Pageable对象,结合Specification来执行分页查询。
接下来,我需要按照步骤来组织回答。可能的结构是:
1. 基础环境准备:定义实体类和Repository接口,确保继承JpaSpecificationExecutor。
2. 实现动态模糊查询:创建Specification,处理不同的查询条件,比如名称模糊匹配、价格范围等。
3. 分页查询实现:在Service层调用Repository的findAll方法,传入Specification和Pageable参数。
4. 示例代码:给出完整的示例代码,包括实体类、Repository接口、Service层的实现,以及可能的Controller层调用。
需要确保代码中的Specification正确使用CriteriaBuilder的like方法,并且处理空值情况,避免不必要的条件。另外,分页的参数如页码、每页数量、排序方式也需要在Pageable中设置。
可能需要注意的地方是,模糊查询时参数需要加上%通配符,或者在Specification中处理。比如用户输入的关键字前后自动添加%,这样like才能正确匹配。
另外,用户可能希望动态组合多个条件,比如同时根据名称和价格范围查询,这时候需要使用Specification的and、or方法来组合多个条件。
在代码示例中,需要展示如何构建动态条件,比如根据是否有名称关键字来决定是否添加名称模糊查询条件,同样处理价格范围是否存在的判断。
还要确保Repository接口正确继承了JpaSpecificationExecutor,这样才能使用findAll方法接受Specification参数。
最后,可能需要提到分页返回的对象Page,包含数据、总页数、总记录数等信息,方便前端分页展示。
需要检查引用的内容是否正确,比如引用[2]和[5]提到JpaSpecificationExecutor和Repository的定义,引用[3]和[4]涉及分页和@Query注解,但用户的问题更偏向于使用Specification,所以重点在引用[2]、[5]的内容。
可能还需要提醒用户关于测试时的注意事项,比如传入的Pageable参数是否正确,以及模糊查询的大小写是否敏感,这取决于数据库的配置。
总之,回答需要结构清晰,逐步引导用户完成实现,并提供可运行的代码示例,同时引用相关的参考资料来支持说明。</think>### Spring Data JPA 自定义分页查询与动态模糊匹配实现示例
#### 1. 基础环境准备
**实体类定义**:
```java
@Entity
public class Product {
@Id
private String id;
private String name;
private Double price;
private String category;
// getter/setter省略
}
```
**Repository接口**需继承`JpaRepository`和`JpaSpecificationExecutor`[^5]:
```java
public interface ProductRepository extends JpaRepository<Product, String>, JpaSpecificationExecutor<Product> {
}
```
---
#### 2. 实现动态模糊查询条件
通过`Specification`实现动态条件组合:
```java
public class ProductSpecifications {
public static Specification<Product> buildDynamicQuery(String keyword, Double minPrice, Double maxPrice) {
return (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
// 名称模糊匹配(自动添加%)
if (StringUtils.hasText(keyword)) {
predicates.add(cb.like(root.get("name"), "%" + keyword + "%"));
}
// 价格区间过滤
if (minPrice != null) {
predicates.add(cb.ge(root.get("price"), minPrice));
}
if (maxPrice != null) {
predicates.add(cb.le(root.get("price"), maxPrice));
}
return cb.and(predicates.toArray(new Predicate[0]));
};
}
}
```
---
#### 3. 分页查询实现
**Service层调用**:
```java
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
public Page<Product> searchProducts(String keyword, Double minPrice, Double maxPrice, int page, int size) {
Specification<Product> spec = ProductSpecifications.buildDynamicQuery(keyword, minPrice, maxPrice);
Pageable pageable = PageRequest.of(page, size, Sort.by("price").descending());
return productRepository.findAll(spec, pageable);
}
}
```
---
#### 4. 完整示例调用
**Controller层**:
```java
@RestController
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping("/products")
public ResponseEntity<Page<Product>> search(
@RequestParam(required = false) String keyword,
@RequestParam(required = false) Double minPrice,
@RequestParam(required = false) Double maxPrice,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
return ResponseEntity.ok(
productService.searchProducts(keyword, minPrice, maxPrice, page, size)
);
}
}
```
---
#### 关键点说明
1. **动态条件构建**:`Specification`通过`Predicate`组合条件,`cb.like()`实现模糊查询,注意参数需手动添加`%`符号[^2]
2. **分页控制**:`PageRequest.of()`可指定页码、每页大小及排序规则[^3]
3. **空值处理**:通过`required = false`标记非必传参数,条件构造时自动过滤空值
4. **返回结果**:`Page`对象包含分页数据、总页数、总记录数等元信息[^4]
---
阅读全文
相关推荐










