Contents

Hibernate 标准查询简介

1. 概述

在本教程中,我们将讨论一个非常有用的 JPA 特性——条件查询。

它使我们能够在不执行原始 SQL 的情况下编写查询,并为我们提供对查询的一些面向对象的控制,这是 Hibernate 的主要特性之一。Criteria API 允许我们以编程方式构建条件查询对象,我们可以在其中应用不同类型的过滤规则和逻辑条件。

**从 Hibernate 5.2 开始,不推荐使用 Hibernate Criteria API,新的开发集中在 JPA Criteria API。**我们将探索如何使用 Hibernate 和 JPA 来构建 Criteria Queries。

2. Maven依赖

为了说明 API,我们将使用参考 JPA 实现 Hibernate。

要使用 Hibernate,我们将确保将其最新版本添加到我们的pom.xml文件中:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>   
    <version>5.3.2.Final</version>
</dependency>

我们可以在这里找到最新版本的 Hibernate

3. 使用标准的简单示例

让我们首先看看如何使用 Criteria Queries 检索数据。我们将研究如何从数据库中获取特定类的所有实例。 我们有一个Item类,它代表数据库中的元组*“ITEM”*:

public class Item implements Serializable {
    private Integer itemId;
    private String itemName;
    private String itemDescription;
    private Integer itemPrice;
   // standard setters and getters
}

让我们看一个简单的条件查询,它将从数据库中检索*“ITEM”*的所有行:

Session session = HibernateUtil.getHibernateSession();
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Item> cr = cb.createQuery(Item.class);
Root<Item> root = cr.from(Item.class);
cr.select(root);
Query<Item> query = session.createQuery(cr);
List<Item> results = query.getResultList();

上面的查询是如何获取所有项目的简单演示。让我们一步一步看:

  1. SessionFactory对象创建Session的实例
  2. 通过调用*getCriteriaBuilder()*方法创建 CriteriaBuilder的实例
  3. 通过调用CriteriaBuilder createQuery()方法创建CriteriaQuery的实例
  4. 通过调用Session createQuery()方法创建一个Query实例
  5. 调用Query对象的*getResultList()*方法,给我们结果

现在我们已经介绍了基础知识,让我们继续讨论条件查询的一些功能。

3.1. 使用表达式

CriteriaBuilder可用于根据特定条件限制查询结果,**方法是使用CriteriaQuery where()方法并提供由CriteriaBuilder创建的表达式。

让我们看一些常用的表达式示例。

为了获得价格超过 1000 的物品:

cr.select(root).where(cb.gt(root.get("itemPrice"), 1000));

接下来,获取itemPrice小于 1000 的项目:

cr.select(root).where(cb.lt(root.get("itemPrice"), 1000));

具有itemName的项目包含Chair

cr.select(root).where(cb.like(root.get("itemName"), "%chair%"));

itemPrice介于 100 和 200 之间的记录:

cr.select(root).where(cb.between(root.get("itemPrice"), 100, 200));

Skate BoardPaintGlue中具有itemName的项目:

cr.select(root).where(root.get("itemName").in("Skate Board", "Paint", "Glue"));

检查给定属性是否为空:

cr.select(root).where(cb.isNull(root.get("itemDescription")));

检查给定属性是否不为空:

cr.select(root).where(cb.isNotNull(root.get("itemDescription")));

我们还可以使用方法isEmpty()isNotEmpty()来测试类中的List是否为空。

此外,我们可以结合上述两个或多个比较。Criteria API 允许我们轻松地链接表达式

Predicate[] predicates = new Predicate[2];
predicates[0] = cb.isNull(root.get("itemDescription"));
predicates[1] = cb.like(root.get("itemName"), "chair%");
cr.select(root).where(predicates);

要添加两个具有逻辑运算的表达式:

Predicate greaterThanPrice = cb.gt(root.get("itemPrice"), 1000);
Predicate chairItems = cb.like(root.get("itemName"), "Chair%");

具有上述定义条件的项目与逻辑* OR *连接:

cr.select(root).where(cb.or(greaterThanPrice, chairItems));

要获取与上述定义的条件匹配的项目,并使用逻辑* AND *加入:

cr.select(root).where(cb.and(greaterThanPrice, chairItems));

3.2. 排序

现在我们知道了Criteria的基本用法,让我们看看 Criteria 的排序功能。

在以下示例中,我们按名称升序排列列表,然后按价格降序排列:

cr.orderBy(
  cb.asc(root.get("itemName")), 
  cb.desc(root.get("itemPrice")));

在下一节中,我们将了解如何执行聚合函数。

3.3. 投影、聚合和分组函数

现在让我们看看不同的聚合函数。

获取行数:

CriteriaQuery<Long> cr = cb.createQuery(Long.class);
Root<Item> root = cr.from(Item.class);
cr.select(cb.count(root));
Query<Long> query = session.createQuery(cr);
List<Long> itemProjected = query.getResultList();

以下是聚合函数的示例——Average的聚合函数:

CriteriaQuery<Double> cr = cb.createQuery(Double.class);
Root<Item> root = cr.from(Item.class);
cr.select(cb.avg(root.get("itemPrice")));
Query<Double> query = session.createQuery(cr);
List avgItemPriceList = query.getResultList();

其他有用的聚合方法是sum()max()min()、*count()*等。

3.4. CriteriaUpdate

从 JPA 2.1 开始,支持使用Criteria API 执行数据库更新。

CriteriaUpdate有一个*set()*方法,可用于为数据库记录提供新值:

CriteriaUpdate<Item> criteriaUpdate = cb.createCriteriaUpdate(Item.class);
Root<Item> root = criteriaUpdate.from(Item.class);
criteriaUpdate.set("itemPrice", newPrice);
criteriaUpdate.where(cb.equal(root.get("itemPrice"), oldPrice));
Transaction transaction = session.beginTransaction();
session.createQuery(criteriaUpdate).executeUpdate();
transaction.commit();

在上面的代码片段中,我们从CriteriaBuilder创建了一个CriteriaUpdate<Item>实例,并使用它的set()方法为itemPrice提供新值。为了更新多个属性,我们只需要多次调用*set()*方法。

3.5. CriteriaDelete

CriteriaDelete使用Criteria API 启用删除操作。

我们只需要创建一个CriteriaDelete实例并使用*where()*方法来应用限制:

CriteriaDelete<Item> criteriaDelete = cb.createCriteriaDelete(Item.class);
Root<Item> root = criteriaDelete.from(Item.class);
criteriaDelete.where(cb.greaterThan(root.get("itemPrice"), targetPrice));
Transaction transaction = session.beginTransaction();
session.createQuery(criteriaDelete).executeUpdate();
transaction.commit();

4. 优于 HQL

在前面的部分中,我们介绍了如何使用 Criteria Queries。

显然,Criteria Queries 优于 HQL 的主要和最有力的优势是漂亮、干净、面向对象的 API。

与普通 HQL 相比,我们可以简单地编写更灵活、更动态的查询。可以使用 IDE 重构逻辑,并具有 Java 语言本身的所有类型安全优势。

当然,也有一些缺点,尤其是在更复杂的连接方面。

因此,我们通常必须使用最好的工具来完成这项工作——在大多数情况下可以是 Criteria API,但在某些情况下,我们肯定需要降低级别。