1. Introduction
1.绪论
In this tutorial, we’ll discuss defining indexes using JPA’s @Index annotation. Through examples, we’ll learn how to define our first index using JPA and Hibernate. After that, we’re going to modify the definition showing additional ways to customize the index.
在本教程中,我们将讨论使用JPA的@Index注解来定义索引。通过实例,我们将学习如何使用JPA和Hibernate定义我们的第一个索引。之后,我们将修改定义,展示定制索引的其他方法。
2. @Index Annotation
2.@Index注释
Let’s begin by making a quick recap. The database index is a data structure that improves the speed of data retrieval operations on a table at the cost of additional writes and storage space. Mostly, it’s a copy of selected columns of data from a single table. We should create indexes to increase performance on our persistence layer.
让我们首先做一个简单的回顾。数据库索引是一种数据结构,可以提高表的数据检索操作的速度,但要付出额外的写入和存储空间。大多数情况下,它是一个对单个表中选定的数据列的复制。我们应该创建索引来提高持久化层的性能。
JPA allows us to achieve that by defining indexes from our code using @Index. This annotation is interpreted by the schema generation process, creating artifacts automatically. Note that it’s not necessary to specify any index for our entities.
JPA允许我们通过使用@Index从我们的代码中定义索引来实现这一点。这个注解会被模式生成过程解释,自动创建工件。注意,没有必要为我们的实体指定任何索引。
Now, let’s take a look at the definition.
现在,让我们看看这个定义。
2.1. javax.persistence.Index
2.1. javax.persistence.Index
The index support has been finally added in the JPA 2.1 specification by javax.persistence.Index. This annotation let us define an index for our table and customize it accordingly:
在JPA 2.1规范中,最终通过javax.persistence.Index添加了索引支持。这个注解让我们为我们的表定义一个索引,并对其进行相应的定制。
@Target({})
@Retention(RUNTIME)
public @interface Index {
String name() default "";
String columnList();
boolean unique() default false;
}
As we can see, only the columnList attribute is mandatory, which we have to define. We’ll take a better look at each of the parameters later, going through examples.
我们可以看到,只有columnList属性是强制性的,我们必须定义它。我们稍后将通过实例更好地观察每个参数。
One aspect to note here is that the annotation doesn’t support changing the default indexing algorithm — btree.
这里需要注意的一个方面是,该注释不支持改变默认的索引算法–btree。
2.2. JPA vs. Hibernate
2.2.JPA与Hibernate的对比
We know that JPA is only a specification. To work correctly, we also need to specify a persistence provider. By default, the Hibernate Framework is JPA’s implementation delivered by Spring. More about it, you can read here.
我们知道,JPA只是一个规范。为了正确工作,我们还需要指定一个持久化提供者。默认情况下,Hibernate框架是由Spring提供的JPA的实现。关于它的更多信息,你可以阅读这里。
We should remember the index support has been added to the JPA very late. Before that, many ORM Frameworks support indexes by introducing their own custom implementation, which might work differently. The Hibernate Framework also did it and introduced the org.hibernate.annotations.Index annotation. While working with that framework, we must be careful that it has been deprecated since the JPA 2.1 specification support, and we should use the JPA’s one.
我们应该记住,索引支持是很晚才被添加到JPA中的。在此之前,许多ORM框架通过引入他们自己的自定义实现来支持索引,这些实现的工作方式可能有所不同。Hibernate框架也做到了这一点,并引入了org.hibernate.annotations.Index注解。在使用该框架时,我们必须注意,自从JPA 2.1规范支持以来,它已经被废弃了,我们应该使用JPA的那个。
Now when we have some technical background, we can go through examples and define our first index in JPA.
现在,当我们有了一些技术背景,我们可以通过实例,在JPA中定义我们的第一个索引。
3. Defining the @Index
3.定义@Index
In this section, we’re implementing our index. Later, we’ll try to modify it, presenting different customization possibilities.
在这一部分,我们正在实现我们的索引。稍后,我们将尝试修改它,提出不同的定制可能性。
Before we start, we need to initialize our project properly and define a model.
在开始之前,我们需要正确初始化我们的项目并定义一个模型。
Let’s implement a Student entity:
我们来实现一个Student实体。
@Entity
@Table
public class Student implements Serializable {
@Id
@GeneratedValue
private Long id;
private String firstName;
private String lastName;
// getters, setters
}
When we have our model, let’s implement the first index. All we have to do is add an @Index annotation. We do that in the @Table annotation under the indexes attribute. Let’s remember to specify the name of the column:
当我们有了我们的模型,让我们来实现第一个索引。我们所要做的就是添加一个@Index注解。我们在indexes属性下的@Table注解中这样做。让我们记住指定列的名称。
@Table(indexes = @Index(columnList = "firstName"))
We’ve declared the very first index using the firstName column. When we execute the schema creation process, we can validate it:
我们已经使用firstName列声明了第一个索引。当我们执行模式创建过程时,我们可以对它进行验证。
[main] DEBUG org.hibernate.SQL -
create index IDX2gdkcjo83j0c2svhvceabnnoh on Student (firstName)
Now, it’s time to modify our declaration showing additional features.
现在,是时候修改我们的声明,显示额外的功能。
3.1. @Index Name
3.1 @Index 名称
As we can see, our index must have a name. By default, if we don’t specify so, it’s a provider-generated value. When we want to have a custom label, we should simply add the name attribute:
正如我们所看到的,我们的索引必须有一个名字。默认情况下,如果我们不这样指定,它就是一个提供者生成的值。当我们想有一个自定义的标签时,我们应该简单地添加name属性。
@Index(name = "fn_index", columnList = "firstName")
This variant creates an index with a user-defined name:
这个变体以用户定义的名称创建一个索引。
[main] DEBUG org.hibernate.SQL -
create index fn_index on Student (firstName)
Moreover, we can create our index in the different schema by specifying the schema’s name in the name:
此外,我们可以通过在name中指定模式的名称,在不同的模式中创建我们的索引。
@Index(name = "schema2.fn_index", columnList = "firstName")
@Index(name = "schema2.fn_index", columnList = "firstName")/code>
3.2. Multicolumn @Index
3.2. 多列@Index
Now, let’s take a closer look at the columnList syntax:
现在,让我们仔细看看columnList的语法。
column ::= index_column [,index_column]*
index_column ::= column_name [ASC | DESC]
As we already know, we can specify the column names to be included in the index. Of course, we can specify multiple columns to the single index. We do that by separating the names by a comma:
正如我们已经知道的,我们可以指定包含在索引中的列名。当然,我们可以为单个索引指定多个列。我们通过用逗号来分隔列名来做到这一点。
@Index(name = "mulitIndex1", columnList = "firstName, lastName")
@Index(name = "mulitIndex2", columnList = "lastName, firstName")
[main] DEBUG org.hibernate.SQL -
create index mulitIndex1 on Student (firstName, lastName)
[main] DEBUG org.hibernate.SQL -
create index mulitIndex2 on Student (lastName, firstName)
Note that the persistence provider must observe the specified ordering of the columns. In our example, indexes are slightly different, even if they specify the same set of columns.
注意,持久化提供者必须遵守指定的列的顺序。在我们的例子中,索引略有不同,即使它们指定了相同的列集。
3.3. @Index Order
3.3.@Index顺序
As we reviewed the syntax in the previous section, we also can specify ASC (ascending) and DESC (descending) values after the column_name. We use it to set the sort order of the values in the indexed column:
正如我们在上一节所回顾的语法,我们还可以在ASC(升序)和DESC(降序)值之后指定column_name。我们用它来设置索引列中数值的排序顺序。
@Index(name = "mulitSortIndex", columnList = "firstName, lastName DESC")
[main] DEBUG org.hibernate.SQL -
create index mulitSortIndex on Student (firstName, lastName desc)
We can specify the order for each column. If we don’t, the ascending order is assumed.
我们可以指定每一列的顺序。如果我们不这样做,就会假定升序的顺序。
3.4. @Index Uniqueness
3.4.@Index独特性
The last optional parameter is a unique attribute, which defines whether the index is unique. A unique index ensures that the indexed fields don’t store duplicate values. By default, it’s false. If we want to change it, we can declare:
最后一个可选参数是一个unique属性,它定义了索引是否是唯一的。一个唯一的索引可以确保被索引的字段不存储重复的值。默认情况下,它是false。如果我们想改变它,我们可以声明。
@Index(name = "uniqueIndex", columnList = "firstName", unique = true)
[main] DEBUG org.hibernate.SQL -
alter table Student add constraint uniqueIndex unique (firstName)
When we create an index in that way, we add a uniqueness constraint on our columns, similarly, how as a unique attribute on @Column annotation do. @Index has an advantage over @Column due to the possibility to declare multi-column unique constraint:
当我们以这种方式创建索引时,我们在我们的列上添加了一个唯一性约束,类似于@Column注释上的unique属性。@Index比@Column更有优势,因为它可以声明多列唯一性约束。
@Index(name = "uniqueMulitIndex", columnList = "firstName, lastName", unique = true)
3.5. Multiple @Index on a Single Entity
3.5.一个实体上的多个@Index
So far, we’ve implemented different variants of the index. Of course, we’re not limited to declaring a single index on the entity. Let’s collect our declarations and specify every single index at once. We do that by repeating @Index annotation in braces and separated by a comma:
到目前为止,我们已经实现了索引的不同变体。当然,我们并不局限于在实体上声明单一的索引。让我们收集我们的声明并一次性指定每一个索引。我们通过重复@Index注解来做到这一点,注解放在大括号里,用逗号隔开。
@Entity
@Table(indexes = {
@Index(columnList = "firstName"),
@Index(name = "fn_index", columnList = "firstName"),
@Index(name = "mulitIndex1", columnList = "firstName, lastName"),
@Index(name = "mulitIndex2", columnList = "lastName, firstName"),
@Index(name = "mulitSortIndex", columnList = "firstName, lastName DESC"),
@Index(name = "uniqueIndex", columnList = "firstName", unique = true),
@Index(name = "uniqueMulitIndex", columnList = "firstName, lastName", unique = true)
})
public class Student implements Serializable
What is more, we can also create multiple indexes for the same set of columns.
更重要的是,我们还可以为同一组列创建多个索引。
3.6. Primary Key
3.6.主键
When we talk about indexes, we have to stop for a while at primary keys. As we know, every entity managed by the EntityManager must specify an identifier that is mapped into the primary key.
当我们谈论索引的时候,我们必须在主键上停一下。正如我们所知,由EntityManager管理的每个实体都必须指定一个标识符,该标识符被映射到主键中。
Generally, the primary key is a specific type of unique index. It’s worth adding that we don’t have to declare the definition of this key in the way presented before. Everything is done automatically by the @Id annotation.
一般来说,主键是一种特殊类型的唯一索引。值得补充的是,我们不需要按照之前介绍的方式来声明这个键的定义。一切都由@Id注解自动完成。
3.7. Non-entity @Index
3.7.非实体@Index
After we’ve learned different ways to implement indexes, we should mention that @Table isn’t the only place to specify them. In the same way, we can declare indexes in @SecondaryTable, @CollectionTable, @JoinTable, @TableGenerator annotations. Those examples aren’t covered in this article. For more details, please check the javax.persistence JavaDoc.
在我们学习了实现索引的不同方法之后,我们应该提到,@Table并不是唯一可以指定索引的地方。同样,我们可以在@SecondaryTable, @CollectionTable, @JoinTable, @TableGenerator 注释中声明索引。这些例子在本文中并没有涉及。更多细节,请查看javax.persistence JavaDoc。
4. Conclusion
4.总结
In this article, we discussed declaring indexes using JPA. We started by reviewing the general knowledge about them. Later we implemented our first index and, through examples, learned how to customize it by changing name, included columns, order, and uniqueness. In the end, we talked about primary keys and additional ways and places where we can declare them.
在这篇文章中,我们讨论了使用JPA声明索引的问题。我们首先回顾了关于索引的一般知识。后来我们实现了我们的第一个索引,并通过实例了解了如何通过改变名称、包含的列、顺序和唯一性来定制它。最后,我们谈到了主键以及我们可以声明它们的其他方式和位置。
As always, the examples from the article are available over on GitHub.
像往常一样,文章中的例子可以在GitHub上找到。