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();
上面的查询是如何获取所有项目的简单演示。让我们一步一步看:
- 从SessionFactory对象创建Session的实例
- 通过调用*getCriteriaBuilder()*方法创建 CriteriaBuilder的实例
- 通过调用CriteriaBuilder createQuery()方法创建CriteriaQuery的实例
- 通过调用Session createQuery()方法创建一个Query实例
- 调用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 Board、Paint和Glue中具有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,但在某些情况下,我们肯定需要降低级别。