業務開發中常面臨多條件組合查詢需求,若為每種組合寫專用方法會導致代碼爆炸。Spring Data JPA 提供兩種基於 Criteria API 的動態查詢方案,本文從原理到實戰全面對比。
UserInfo_)編譯期檢查屬性名,避免運行時拼接 SQL 錯誤CriteriaQuery、Predicate 替代字符串拼接適用於需要精細控制查詢結構(如動態 SELECT 字段、複雜 JOIN)的場景。
public List<UserInfo> getUserInfo(String name, int age, int high) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<UserInfo> query = cb.createQuery(UserInfo.class);
Root<UserInfo> root = query.from(UserInfo.class);
Predicate predicate = null;
if (name != null) {
Predicate p = cb.equal(root.get(UserInfo_.name), name);
predicate = (predicate == null) ? p : cb.and(predicate, p);
}
if (age != 0) {
Predicate p = cb.equal(root.get(UserInfo_.age), age);
predicate = (predicate == null) ? p : cb.and(predicate, p);
}
if (high != 0) {
Predicate p = cb.equal(root.get(UserInfo_.high), high);
predicate = (predicate == null) ? p : cb.and(predicate, p);
}
query.where(predicate);
return em.createQuery(query).getResultList();
}
DAO 繼承 JpaSpecificationExecutor<T>,自動獲得分頁、排序、動態條件查詢能力,無需手動管理 EntityManager。
public interface UserInfoDao extends PagingAndSortingRepository<UserInfo, String>,
JpaSpecificationExecutor<UserInfo> {}
構建 Specification 匿名類,將條件構建邏輯封裝:
public static Specification<UserInfo> getSpec(final String name, final int age, final int high) {
return (root, query, cb) -> {
Predicate predicate = null;
if (name != null) predicate = cb.and(predicate, cb.equal(root.get(UserInfo_.name), name));
if (age != 0) predicate = cb.and(predicate, cb.equal(root.get(UserInfo_.age), age));
if (high != 0) predicate = cb.and(predicate, cb.equal(root.get(UserInfo_.high), high));
return predicate;
};
}
調用極簡潔:
List<UserInfo> list = userInfoDao.findAll(getSpec("張三", 25, 180));
Page<UserInfo> page = userInfoDao.findAll(getSpec(null, 0, 0), PageRequest.of(0, 10, Sort.by("age").descending()));
| 維度 | 手動 CriteriaQuery | Specification |
|---|---|---|
| 靈活度 | 極高(控制 SELECT/JOIN/GROUP BY) | 僅 WHERE 條件動態 |
| 代碼量 | 較多 | 極少 |
| 分頁排序 | 手動實現 | 內置支持 |
| 適用場景 | 複雜報表、多表關聯 | 常規業務條件查詢 |
使用 @StaticMetamodel 註解的類(如 UserInfo_)可由 hibernate-jpamodelgen 編譯期自動生成,避免手寫維護成本。
項目源碼下載:springdatajpademo_jb51.rar