1. 概述
在本教程中,我们将展示如何在 Spring Data JPA 中处理查询方法中的 null 参数。
有些时候我们希望在查询中将 null 参数理解为 IS NULL
条件,用于查找字段为 null 的记录;而另一些时候,我们希望忽略 null 参数,不在 WHERE 子句中包含该条件。
下面我们会分别演示这两种方式的实现。
2. 快速示例
假设我们有一个 Customer
实体类:
@Entity
public class Customer {
@Id
@GeneratedValue
private long id;
private String name;
private String email;
public Customer(String name, String email) {
this.name = name;
this.email = email;
}
// getters/setters
}
同时,我们有一个 JPA Repository:
public interface CustomerRepository extends JpaRepository<Customer, Long> {
// method1
// method2
}
我们的目标是根据 name
和 email
查询客户信息。我们会实现两个方法:
✅ 一个将 null 参数视为 IS NULL
✅ 另一个则忽略 null 参数,不将其加入查询条件中
3. Null 参数的处理方式
3.1. 使用 IS NULL 查询
Spring Data JPA 默认会将 null 参数解释为 IS NULL
。这意味着如果你传入的参数为 null,生成的 JPQL 查询中会自动加上 IS NULL
条件。
我们只需定义如下方法:
List<Customer> findByNameAndEmail(String name, String email);
例如,传入 name = "D"
,email = null
时,生成的 JPQL 条件会是:
customer0_.email is null
测试代码如下:
@Before
public void before() {
entityManager.persist(new Customer("A", "[email protected]"));
entityManager.persist(new Customer("D", null));
entityManager.persist(new Customer("D", "[email protected]"));
}
@Test
public void testFindByNullEmail() {
List<Customer> customers = repository.findByNameAndEmail("D", null);
assertEquals(1, customers.size());
Customer actual = customers.get(0);
assertEquals(null, actual.getEmail());
assertEquals("D", actual.getName());
}
✅ 该方法简单粗暴,适合 null 有明确语义的场景。
3.2. 通过多个查询方法忽略 null 参数
如果我们想忽略某个参数(如 email),最直接的方式是添加一个只接受部分参数的方法:
List<Customer> findByName(String name);
⚠️ 但这种方式在参数组合多的情况下会变得难以维护。比如你有 4 个可选字段,组合就会爆炸式增长,导致代码冗余严重。
3.3. 使用 @Query 注解忽略 null 参数
更灵活的方式是使用 @Query
注解,手动控制 JPQL 查询语句,实现动态查询逻辑。
@Query("SELECT c FROM Customer c WHERE (:name is null or c.name = :name) and (:email is null or c.email = :email)")
List<Customer> findCustomerByNameAndEmail(
@Param("name") String name,
@Param("email") String email);
这段 JPQL 的逻辑是:
- 如果
name
为 null,则:name is null or c.name = :name
恒为 true - 同理,如果
email
为 null,该条件也恒为 true
测试代码如下:
List<Customer> customers = repository.findCustomerByNameAndEmail("D", null);
assertEquals(2, customers.size());
✅ 这样我们就能忽略 null 参数,查出所有 name 为 "D" 的记录,不管 email 是否为 null。
⚠️ 但是要注意,这种方式依赖数据库优化器来跳过不必要的条件,在大数据量或复杂查询下可能会有性能问题。
4. 总结与展望
我们介绍了两种处理 null 参数的方式:
方式 | 行为 | 示例 |
---|---|---|
默认行为 | null 被解释为 IS NULL |
findByNameAndEmail("D", null) |
自定义 JPQL | 忽略 null 参数 | 使用 @Query 注解 |
✅ 默认行为适用于 null 有业务含义的场景,比如查找 email 为空的用户。
✅ 自定义 JPQL 更灵活,适合参数可选、组合多的场景。
未来可能会支持 @NullMeans
注解(目前还在提案中),可以更优雅地控制 null 的语义:
@NullMeans(NullHandling.IS_NULL)
List<Customer> findByName(String name);
完整代码示例可以在 GitHub 上查看:Spring Data JPA Filtering 示例