The Exists Query in Spring Data – Spring Data中的Exists查询

最后修改: 2019年 4月 3日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.绪论

In many data-centric applications, situations can arise where we need to check whether a particular object already exists.

在许多以数据为中心的应用中,可能会出现这样的情况:我们需要检查一个特定的对象是否已经存在。

In this tutorial, we’ll discuss several ways to achieve this using Spring Data and JPA.

在本教程中,我们将讨论使用Spring Data和JPA来实现这一目标的几种方法。

2. Sample Entity

2.实体样本

To set the stage for our examples, we’ll create an entity Car with two properties, model and power:

为了给我们的例子做好铺垫,我们将创建一个实体Car,有两个属性:modelpower

@Entity
public class Car {

    @Id
    @GeneratedValue
    private int id;

    private Integer power;
    private String model;
    
    // getters, setters, ...
}

3. Searching by ID

3.按身份证搜索

The JpaRepository interface exposes the existsById method, which checks if an entity with the given id exists in the database:

JpaRepository接口暴露了existsById方法,该方法检查数据库中是否存在一个给定id的实体。

int searchId = 2; // ID of the Car
boolean exists = repository.existsById(searchId)

Let’s assume that searchId is the id of a Car we created during test setup. For the sake of test repeatability, we should never use a hard-coded number (for example “2”) because the id property of a Car is likely auto-generated and could change over time. The existsById query is the easiest, but least flexible way of checking for an object’s existence.

让我们假设searchId是我们在测试设置期间创建的Carid。为了保证测试的可重复性,我们不应该使用一个硬编码的数字(例如 “2”),因为id属性的Car很可能是自动生成的,并可能随着时间的推移而改变。existsById查询是检查对象是否存在的最简单、但最不灵活的方法

4. Using a Derived Query Method

4.使用派生查询法

We can also use Spring’s derived query method feature to formulate our query. In our example, we want to check if a Car with a given model name exists; therefore, we devise the following query method:

我们还可以使用Spring的派生查询方法功能来制定我们的查询。在我们的例子中,我们想检查具有给定模型名称的Car是否存在;因此,我们设计了以下查询方法。

boolean existsCarByModel(String model);

It’s important to note that the naming of the method isn’t arbitrary, it must follow certain rules. Spring will then generate the proxy for the repository such that it can derive the SQL query from the name of the method. Modern IDEs, like IntelliJ IDEA, will provide syntax completion.

需要注意的是,方法的命名并不是任意的,它必须遵循一定的规则。然后Spring将为资源库生成代理,这样它就可以从方法的名称中推导出SQL查询。现代IDE,如IntelliJ IDEA,将提供语法完成。

When queries get more complex, such as incorporating ordering, limiting results, and including several query criteria, these method names can get quite long, right up to the point of illegibility. Derived query methods also might seem a bit magical because of their implicit and “by convention” nature.

当查询变得更加复杂时,例如包含排序、限制结果和包括几个查询条件,t这些方法名称可能会变得相当长,甚至到了无法辨认的地步。派生查询方法也可能因为其隐含的和 “约定俗成 “的性质而显得有些神奇。

Nevertheless, they can come in handy when clean and uncluttered code is important, and when developers want to rely on a well-tested framework.

尽管如此,当干净整洁的代码很重要时,以及当开发者想依靠一个经过良好测试的框架时,它们可以派上用场。

5. Searching by Example

5.按例子搜索

An Example is a very powerful way of checking for existence because it uses ExampleMatchers to dynamically build the query. So whenever we require dynamicity, this is a good way to do it. A comprehensive explanation of Spring’s ExampleMatchers and how to use them can be found in our Spring Data Query article.

Example是一种非常强大的检查存在性的方式,因为它使用ExampleMatchers来动态地构建查询。因此,只要我们需要动态性,这就是一种很好的方式。关于Spring的ExampleMatchers以及如何使用它们的全面解释可以在我们的Spring数据查询文章中找到。

5.1. The Matcher

5.1.匹配器

Suppose we want to search for model names in a case-insensitive way. We’ll start by creating our ExampleMatcher:

假设我们想以不区分大小写的方式来搜索模型名称。我们将从创建我们的ExampleMatcher开始。

ExampleMatcher modelMatcher = ExampleMatcher.matching()
  .withIgnorePaths("id") 
  .withMatcher("model", ignoreCase());

Note that we must explicitly ignore the id path because id is the primary key, and those are picked up automatically by default.

请注意,我们必须明确地忽略id路径,因为id是主键,而这些路径在默认情况下被自动拾取。

5.2. The Probe

5.2.探针

Next, we need to define a so-called “probe,” which is an instance of the class we want to look up. It has all the search-relevant properties set. We then connect it to our nameMatcher, and execute the query:

接下来,我们需要定义一个所谓的 “探针”,它是我们想要查找的类的一个实例。它有所有与搜索相关的属性。然后我们把它连接到我们的nameMatcher,并执行查询。

Car probe = new Car();
probe.setModel("bmw");
Example<Car> example = Example.of(probe, modelMatcher);
boolean exists = repository.exists(example);

With great flexibility comes great complexity, and as powerful as the ExampleMatcher API may be, using it will produce quite a few lines of extra code. We suggest using it in dynamic queries, or if no other method fits our needs.

巨大的灵活性伴随着巨大的复杂性,尽管ExampleMatcher API可能很强大,但使用它将产生相当多的额外代码行。我们建议在动态查询中使用它,或者如果没有其他方法适合我们的需求

6. Writing a Custom JPQL Query With Exists Semantics

6.编写具有存在语义的自定义JPQL查询

The last method we’ll examine uses JPQL (Java Persistence Query Language) to implement a custom query with existssemantics:

我们要研究的最后一个方法是使用JPQL(Java Persistence Query Language)来实现一个带有existssemantics的自定义查询。

@Query("select case when count(c)> 0 then true else false end from Car c where lower(c.model) like lower(:model)")
boolean existsCarLikeCustomQuery(@Param("model") String model);

The idea is to execute a case-insensitive count query based on the model property, evaluate the return value, and map the result to a Java boolean. Again, most IDEs have pretty good support for JPQL statements.

这个想法是根据model属性执行不区分大小写的count查询,评估返回值,并将结果映射到Java boolean同样,大多数IDE对JPQL语句有相当好的支持。

Custom JPQL queries can be seen as an alternative to derived methods, and are often a good choice when we’re comfortable with SQL-like statements and don’t mind the additional @Query annotations.

自定义 JPQL 查询可以被看作是派生方法的一种替代方法,当我们对类似 SQL 的语句感到满意并且不介意额外的 @Query 注解时,这通常是一个不错的选择。

7. Conclusion

7.结语

In this article, we learned how to check if an object exists in a database using Spring Data and JPA. There’s no hard and fast rule when to use each method because it largely depends on the use case at hand and personal preference.

在这篇文章中,我们学习了如何使用Spring Data和JPA来检查一个对象是否存在于数据库中。何时使用每种方法并没有硬性规定,因为这主要取决于手头的用例和个人的偏好。

As a good rule of thumb though, given a choice, developers should always lean toward the more straightforward method for reasons of robustness, performance, and code clarity. Also, once decided on either derived queries or custom JPQL queries, it’s a good idea to stick with that choice for as long as possible to ensure a consistent coding style.

不过,作为一个好的经验法则,在有选择的情况下,开发人员应该总是倾向于更直接的方法,以保证稳健性、性能和代码的清晰性。此外,一旦决定使用派生查询或自定义JPGL查询,最好是尽可能地坚持这种选择,以确保编码风格的一致性。

A complete source code example can be found over on GitHub.

GitHub上可以找到一个完整的源代码示例。