在本教程中,我们将讨论一个非常有用的 JPA 功能 — 条件查询。
它使我们能够在不执行原始SQL的情况下编写查询,并为我们提供了一些面向对象的查询控制,这是Hibernate的主要功能之一。标准 API 允许我们以编程方式构建标准查询对象,我们可以在其中应用不同类型的过滤规则和逻辑条件。
从Hibernate5.2开始,Hibernate标准API被弃用,新的开发集中在JPA标准API上。我们将探讨如何使用Hibernate和JPA来构建条件查询。
为了说明 API,我们将使用参考 JPA 实现 Hibernate。
要使用 Hibernate,我们将确保将其最新版本添加到我们的pom.xml文件中:
- <dependency>
- <groupId>org.hibernate</groupId>
- <artifactId>hibernate-core</artifactId>
- <version>5.3.2.Final</version>
- </dependency>
Copy
我们可以在这里找到最新版本的Hibernate。
让我们首先看看如何使用条件查询检索数据。我们将了解如何从数据库中获取特定类的所有实例。
我们有一个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
上面的查询是如何获取所有项目的简单演示。让我们一步一步地看:
现在我们已经介绍了基础知识,让我们继续讨论条件查询的一些功能。
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
现在我们知道了标准的基本用法,让我们看一下标准的排序功能。
在下面的示例中,我们按名称的升序排列列表,然后按价格降序对列表进行排序:
- cr.orderBy(
- cb.asc(root.get("itemName")),
- cb.desc(root.get("itemPrice")));
Copy
在下一节中,我们将了解如何执行聚合函数。
现在让我们看看不同的聚合函数。
获取行计数:
- 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()等。
从 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
条件删除启用使用条件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
在前面的部分中,我们介绍了如何使用条件查询。
显然,与 HQL 相比,标准查询的主要和最强大的优势是漂亮、干净、面向对象的 API。
与普通 HQL 相比,我们可以简单地编写更灵活、更动态的查询。该逻辑可以使用 IDE 进行重构,并具有 Java 语言本身的所有类型安全优势。
当然,也有一些缺点,尤其是在更复杂的连接周围。
因此,我们通常必须使用最适合工作的工具——在大多数情况下,这可能是标准 API,但肯定在某些情况下,我们将不得不降低级别。
在本文中,我们重点介绍了 Hibernate 和 JPA 中标准查询的基础知识以及 API 的一些高级功能。
此处讨论的代码在GitHub 存储库中可用。