Hibernate 中需根據用戶輸入的多個可選條件動態構建查詢(如圖片所示的複雜查詢表單),傳統字符串拼接 HQL 易出錯、難維护、有注入風險。
| 方案 | 特點 | 適用場景 | 學習曲線 |
|---|---|---|---|
| Criteria API (Hibernate 3/4/5) | 類型安全、面向對象、程序化構建、支持投影/聚合 | 動態條件查詢、分頁、排序、複雜關聯 | 中等 |
| JPA CriteriaBuilder (JPA 2.0+) | 標準化、與 Provider 無關、Metamodel 類型安全 | Spring Data JPA 環境、長期維護項目 | 較陡峭 |
| QueryDSL | 流暢 API、代碼生成 Q 類、極佳類型安全、支持 SQL/NoSQL | 大型項目、複雜查詢、團隊追求代碼質量 | 需配置 APT |
| Spring Data JPA Specification | 封裝 JPA Criteria、配合 Repository 使用、可組合、易測試 | Spring Boot 項目、動態條件封裝為業務規則 | 低 |
| 原生 SQL / HQL 字符串拼接 | 靈活、性能可控、支持數據庫特有語法 | 極複雜報表、存儲過程調用、遷移舊代碼 | 低但風險高 |
// 1. 定義 Specification
public class UserSpecs {
public static Specification nameLike(String name) {
return (root, query, cb) ->
name == null ? null : cb.like(root.get("name"), "%" + name + "%");
}
public static Specification ageBetween(Integer min, Integer max) {
return (root, query, cb) -> {
List preds = new ArrayList<>();
if (min != null) preds.add(cb.ge(root.get("age"), min));
if (max != null) preds.add(cb.le(root.get("age"), max));
return cb.and(preds.toArray(new Predicate[0]));
};
}
// 組合多條件
public static Specification byCriteria(UserQueryDTO dto) {
return Specification.where(nameLike(dto.getName()))
.and(ageBetween(dto.getMinAge(), dto.getMaxAge()));
}
}
// 2. Repository 繼承 JpaSpecificationExecutor
public interface UserRepository extends JpaRepository, JpaSpecificationExecutor {}
// 3. Service 中調用
Page page = userRepository.findAll(UserSpecs.byCriteria(dto), pageable);
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery(User.class);
Root root = cq.from(User.class);
List predicates = new ArrayList<>();
if (name != null) predicates.add(cb.like(root.get("name"), "%" + name + "%"));
if (minAge != null) predicates.add(cb.ge(root.get("age"), minAge));
if (maxAge != null) predicates.add(cb.le(root.get("age"), maxAge));
cq.where(cb.and(predicates.toArray(new Predicate[0])));
cq.orderBy(cb.desc(root.get("createTime")));
TypedQuery query = session.createQuery(cq);
query.setFirstResult(offset).setMaxResults(pageSize);
List list = query.getResultList();
查詢表單界面:

數組裝載條件報錯:

最佳回答提供博客鏈接:Hibernate 查詢問題詳解,建議結合官方文檔系統學習。