首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Hibernate Criteria API 完整實戰指南:從基礎查詢到動態條件組裝

     編輯:Java 相關知識

為什麼選 Criteria?

HQL/JPQL 靜態字串難以應對「使用者任意組合查詢條件」的場景。Criteria API 提供型別安全、物件導向、可程式化組裝的查詢建構方式,極適合動態報表、進階搜尋、通用 DAO 等需求。雖然 Hibernate 5.2+ 推薦 JPA Criteria,但傳統 org.hibernate.Criteria 仍廣泛用於存量專案,本文兩者並陳說明。

核心類別速查表

類別/介面用途建立方式
Criteria線上查詢,需 Sessionsession.createCriteria(Entity.class)
DetachedCriteria離線查詢,可序列化跨層傳遞DetachedCriteria.forClass(Entity.class)
RestrictionsCriterion 工廠 (eq, like, between, in...)靜態方法
ProjectionsProjection 工廠 (count, sum, groupProperty...)靜態方法
Order排序 (asc/desc)Order.asc("prop")
ExampleQBE (Query By Example)Example.create(entity)

七大實戰場景

1. 基礎查詢與分頁

Criteria c = session.createCriteria(Product.class);
c.add(Restrictions.like("name", "iPhone%"));
c.addOrder(Order.desc("price"));
c.setFirstResult(0).setMaxResults(20);
List list = c.list();

2. 邏輯組合:AND / OR / NOT

// WHERE (name LIKE 'iPhone%' OR brand='Apple') AND price > 5000
Criterion nameCond = Restrictions.like("name", "iPhone%");
Criterion brandCond = Restrictions.eq("brand", "Apple");
Criterion priceCond = Restrictions.gt("price", 5000);

c.add(Restrictions.and(priceCond, Restrictions.or(nameCond, brandCond)));

// 更複雜用 Conjunction/Disjunction
Disjunction or = Restrictions.disjunction()
    .add(Restrictions.isNull("discount"))
    .add(Restrictions.eq("discount", 0));
c.add(Restrictions.and(priceCond, or));

3. 關聯查詢:createCriteria vs createAlias

// 內連結 Category,並對關聯表加條件
c.createCriteria("category", "cat")           // 回傳新 Criteria 指向 Category
 .add(Restrictions.eq("cat.status", 1));

// 只想加條件不想產生新 Criteria,用 createAlias
c.createAlias("category", "cat")
 .createAlias("supplier", "sup")
 .add(Restrictions.eqProperty("cat.id", "sup.defaultCategoryId"));

4. 動態抓取策略 (FetchMode)

c.setFetchMode("category", FetchMode.JOIN)   // 左外連結一次撈回
 .setFetchMode("tags", FetchMode.SELECT);    // 另發 SQL (預設)

5. 投影與聚合:報表、統計、分組

// SELECT COUNT(*), AVG(price), MAX(price), color FROM Product GROUP BY color
ProjectionList pl = Projections.projectionList()
    .add(Projections.rowCount(), "cnt")
    .add(Projections.avg("price"), "avgPrice")
    .add(Projections.max("price"), "maxPrice")
    .add(Projections.groupProperty("color"), "color");

c.setProjection(pl);
List rows = c.list(); // 每筆: [cnt, avgPrice, maxPrice, color]

// 別名化以便排序/條件
c.setProjection(Projections.projectionList()
    .add(Projections.rowCount(), "cnt")
    .add(Projections.groupProperty("color").as("color"))
).addOrder(Order.desc("cnt"));

6. Query By Example (QBE)

Product probe = new Product();
probe.setBrand("Apple");
probe.setStatus(1);

Example ex = Example.create(probe)
    .excludeZeroes()           // 忽略數值 0
    .ignoreCase()              // 字串不分大小寫
    .enableLike(MatchMode.ANYWHERE); // %value%

c.add(ex);

7. 離線查詢與子查詢

// 子查詢:找出價格高於「同品牌平均價」的產品
DetachedCriteria avgSub = DetachedCriteria.forClass(Product.class, "p2")
    .setProjection(Projections.avg("p2.price"))
    .add(Property.forName("p2.brand").eqProperty("p1.brand"));

Criteria main = session.createCriteria(Product.class, "p1");
main.add(Property.forName("p1.price").gt(avgSub));

Spring 整合:HibernateTemplate.findByCriteria

@Repository
public class ProductDaoImpl extends HibernateDaoSupport implements ProductDao {
    public List findByDetached(DetachedCriteria dc, int offset, int limit) {
        return getHibernateTemplate().execute(session -> {
            Criteria c = dc.getExecutableCriteria(session);
            c.setFirstResult(offset).setMaxResults(limit);
            return c.list();
        });
    }
}

常見坑點與效能提示

  • 避免 Cartesian Product:多對多關聯若同時 JOIN 兩張集合表會爆炸,改用 setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY) 或分兩次查。
  • Projection 後無法直接拿 Entity:setProjection 會改變回傳型別為 Object[] 或 Map,需用 setResultTransformer(Transformers.aliasToBean(DTO.class)) 映射 DTO。
  • 大量資料勿用 list():改用 scroll() 或 iterate() 配合分頁,避免 OOM。
  • 型別安全:新專案優先用 JPA CriteriaBuilder,編譯期檢查屬性名稱。

結語

Criteria API 是 Hibernate 最強大的動態查詢工具。掌握 Restrictions 條件組合、Projections 聚合分組、createAlias 關聯控制、DetachedCriteria 跨層傳遞與子查詢,即可應付 90% 以上的複雜查詢需求,且程式碼可讀、可測、可維護。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved