1. 概述
在本教程中,我们将讨论一个非常有用的 JPA 功能 — 条件查询。
它使我们能够在不执行原始SQL的情况下编写查询,并为我们提供了一些面向对象的查询控制,这是Hibernate的主要功能之一。标准 API 允许我们以编程方式构建标准查询对象,我们可以在其中应用不同类型的过滤规则和逻辑条件。
从Hibernate5.2开始,Hibernate标准API被弃用,新的开发集中在JPA标准API上。我们将探讨如何使用Hibernate和JPA来构建条件查询。
2. Maven 依赖项
为了说明 API,我们将使用参考 JPA 实现 Hibernate。
要使用 Hibernate,我们将确保将其最新版本添加到我们的pom.xml文件中:
<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-core</artifactId> <version>5.3.2.Final</version>
</dependency>
Copy
我们可以在这里找到最新版本的Hibernate。
3. 使用标准的简单示例
让我们首先看看如何使用条件查询检索数据。我们将了解如何从数据库中获取特定类的所有实例。
我们有一个Item类,它表示元组“ITEM”在数据库中:
public class Item implements Serializable {private Integer itemId;private String itemName;private String itemDescription;private Integer itemPrice;// standard setters and getters
}
Copy
让我们看一个简单的条件查询,它将从数据库中检索“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();
Copy
上面的查询是如何获取所有项目的简单演示。让我们一步一步地看:
- 从会话工厂对象创建会话的实例
- 通过调用getCriteriaBuilder()方法创建 CriteriaBuilder的实例
- 通过调用CriteriaBuildercreateQuery()方法创建CriteriaQuery的实例
- 通过调用SessioncreateQuery() 方法创建查询实例
- 调用查询对象的getResultList() 方法,它给了我们结果
现在我们已经介绍了基础知识,让我们继续讨论条件查询的一些功能。
3.1. 使用表达式
CriteriaBuilder 可用于根据特定条件限制查询结果,方法是使用CriteriaQuery where() 方法并提供由 CriteriaBuilder 创建的表达式。
让我们看一些常用表达式的示例。
为了获得价格超过1000的商品:
cr.select(root).where(cb.gt(root.get("itemPrice"), 1000));
Copy
接下来,获取项目价格低于 1000 的项目:
cr.select(root).where(cb.lt(root.get("itemPrice"), 1000));
Copy
具有项目名称的项目包含主席:
cr.select(root).where(cb.like(root.get("itemName"), "%chair%"));
Copy
itemPrice介于 100 和 200 之间的记录:
cr.select(root).where(cb.between(root.get("itemPrice"), 100, 200));
Copy
在滑板,油漆和胶水中具有项目名称的项目:
cr.select(root).where(root.get("itemName").in("Skate Board", "Paint", "Glue"));
Copy
要检查给定属性是否为空,请执行以下操作:
cr.select(root).where(cb.isNull(root.get("itemDescription")));
Copy
要检查给定的属性是否不为空,请执行以下操作:
cr.select(root).where(cb.isNotNull(root.get("itemDescription")));
Copy
我们还可以使用 isEmpty() 和isNotEmpty() 方法来测试类中的List是否为空。
此外,我们可以结合上述两个或多个比较。标准 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);
Copy
添加两个具有逻辑运算的表达式:
Predicate greaterThanPrice = cb.gt(root.get("itemPrice"), 1000);
Predicate chairItems = cb.like(root.get("itemName"), "Chair%");
Copy
具有上述定义条件的项目与逻辑 OR 连接:
cr.select(root).where(cb.or(greaterThanPrice, chairItems));
Copy
要获取与上述定义条件匹配的项,请使用逻辑 AND 联接:
cr.select(root).where(cb.and(greaterThanPrice, chairItems));
Copy
3.2. 排序
现在我们知道了标准的基本用法,让我们看一下标准的排序功能。
在下面的示例中,我们按名称的升序排列列表,然后按价格降序对列表进行排序:
cr.orderBy(cb.asc(root.get("itemName")), cb.desc(root.get("itemPrice")));
Copy
在下一节中,我们将了解如何执行聚合函数。
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();
Copy
以下是聚合函数的示例 -平均值的聚合函数:
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();
Copy
其他有用的聚合方法有sum(),max(),min(),count()等。
3.4.标准更新
从 JPA 2.1 开始,支持使用条件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();
Copy
在上面的代码片段中,我们从CriteriaBuilder创建一个CriteriaUpdate<Item> 的实例,并使用其set() 方法为itemPrice 提供新值。为了更新多个属性,我们只需要多次调用set() 方法。
3.5.条件删除
条件删除启用使用条件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();
Copy
4. 优于 HQL 的优势
在前面的部分中,我们介绍了如何使用条件查询。
显然,与 HQL 相比,标准查询的主要和最强大的优势是漂亮、干净、面向对象的 API。
与普通 HQL 相比,我们可以简单地编写更灵活、更动态的查询。该逻辑可以使用 IDE 进行重构,并具有 Java 语言本身的所有类型安全优势。
当然,也有一些缺点,尤其是在更复杂的连接周围。
因此,我们通常必须使用最适合工作的工具——在大多数情况下,这可能是标准 API,但肯定在某些情况下,我们将不得不降低级别。
5. 结论
在本文中,我们重点介绍了 Hibernate 和 JPA 中标准查询的基础知识以及 API 的一些高级功能。
此处讨论的代码在GitHub 存储库中可用。