Defining Unique Constraints in JPA – 在JPA中定义唯一约束条件

最后修改: 2021年 6月 3日

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

1. Introduction

1.绪论

In this tutorial, we’ll discuss defining unique constraints using JPA and Hibernate.

在本教程中,我们将讨论使用JPA和Hibernate定义唯一约束。

First, we’ll explore unique constraints and how they differ from primary key constraints.

首先,我们将探讨唯一约束以及它们与主键约束的区别。

Then we’ll take a look at JPA’s important annotations, @Column(unique=true) and @UniqueConstraint. We’ll implement them to define the unique constraints on a single column and multiple columns.

然后我们将看看JPA的重要注解,@Column(unique=true) @UniqueConstraint。我们将实现它们来定义单个列和多个列的唯一约束。

Finally, we’ll learn how to define unique constraints on referenced table columns.

最后,我们将学习如何在引用的表列上定义唯一约束。

2. Unique Constraints

2.独特的制约因素

Let’s start with a quick recap. A unique key is a set of single or multiple columns of a table that uniquely identify a record in a database table.

让我们先来简单回顾一下。唯一键是一组表的单列或多列,唯一地识别数据库表中的一条记录。

Both the unique and primary key constraints provide a guarantee for uniqueness for a column or set of columns.

唯一键和主键约束都为一个列或一组列的唯一性提供了保证。

2.1. How It’s Different From Primary Key Constraints?

2.1.它与主键约束有什么不同?

Unique constraints ensure that the data in a column or combination of columns is unique for each row. A table’s primary key, for example, functions as an implicit unique constraint. Hence, the primary key constraint automatically has a unique constraint.

唯一约束确保了一列或一列组合中的数据对每一行都是唯一的。例如,一个表的主键可以作为一个隐含的唯一约束。因此,主键约束自动具有唯一约束。

Furthermore, we can have only one primary key constraint per table. However, there can be multiple unique constraints per table.
Simply put, the unique constraints apply in addition to any constraint entailed by primary key mapping.

此外,我们每个表只能有一个主键约束。然而,每个表可以有多个唯一约束。
简单地说,唯一约束除了适用于主键映射所带来的任何约束外,还适用于唯一约束。

The unique constraints we define are used during table creation to generate the proper database constraints, and may also be used at runtime to order insert, update, or delete statements.

我们定义的唯一约束在创建表的过程中被用来生成适当的数据库约束,也可以在运行时被用来排序插入更新删除语句。

2.2. What Are Single-Column and Multiple-Column Constraints?

2.2.什么是单列和多列约束?

A unique constraint can be either a column constraint or a table constraint. At the table level, we can define unique constraints across multiple columns.

唯一约束可以是一个列约束,也可以是一个表约束。在表一级,我们可以定义多个列的唯一约束。

JPA allows us to define unique constraints in our code using @Column(unique=true) and @UniqueConstraint. These annotations are interpreted by the schema generation process, creating constraints automatically.

JPA允许我们在代码中使用@Column(unique=true)@UniqueConstraint来定义唯一约束。这些注解由模式生成过程解释,自动创建约束。

Before anything else, we should emphasize that column-level constraints apply to a single column, and table-level constraints apply to the whole table.

在做其他事情之前,我们应该强调,列级约束适用于单个列,而表级约束适用于整个表。

We’ll discuss this in more detail in the next sections.

我们将在接下来的章节中更详细地讨论这个问题。

3. Set Up an Entity

3.建立一个实体

An entity in JPA represents a table stored in a database. Every instance of an entity represents a row in the table.

JPA中的实体代表了存储在数据库中的一个表。实体的每一个实例都代表着表中的一行。

Let’s start by creating a domain entity and mapping it to a database table. For this example, we’ll create a Person entity:

让我们从创建一个领域实体并将其映射到数据库表开始。在这个例子中,我们将创建一个Person实体。

@Entity
@Table
public class Person implements Serializable {
    @Id
    @GeneratedValue
    private Long id;  
    private String name;
    private String password;
    private String email;
    private Long personNumber;
    private Boolean isActive;
    private String securityNumber;
    private String departmentCode;
    @JoinColumn(name = "addressId", referencedColumnName = "id")
    private Address address;
   //getters and setters
 }

An address field is a referenced field from the Address entity:

一个address字段是一个来自Address实体的引用字段。

@Entity
@Table
public class Address implements Serializable {
    @Id
    @GeneratedValue
    private Long id;
    private String streetAddress;
    //getters and setters
}

Throughout this tutorial, we’ll use this Person entity to demonstrate our examples.

在本教程中,我们将使用这个Person实体来演示我们的例子。

4. Column Constraints

4.列的限制条件

When we have our model ready, we can implement our first unique constraint.

当我们准备好我们的模型时,我们可以实现我们的第一个唯一约束。

Let’s consider our Person entity that holds the person’s information. We have a primary key for the id column. This entity also holds the PersonNumber, which doesn’t contain any duplicate value. In addition, we can’t define the primary key because our table already has it.

让我们考虑一下我们的Person实体,它持有个人的信息。我们有一个id列的主键。这个实体还持有PersonNumber,,它不包含任何重复的值。此外,我们不能定义主键,因为我们的表已经有了它。

In this case, we can use column unique constraints to make sure that no duplicate values are entered in a PersonNumber field. JPA allows us to achieve this using the @Column annotation with the unique attribute.

在这种情况下,我们可以使用列的唯一约束来确保在PersonNumber字段中没有重复的值被输入。JPA允许我们使用带有unique属性的@Column注解来实现这一点。

In the following sections, we’ll take a look at the @Column annotation, and then learn how to implement it.

在下面的章节中,我们将看一下@Column注解,然后学习如何实现它。

4.1. @Column(unique=true)

4.1@Column(unique=true)

The annotation type Column is used to specify the mapped column for a persistent property or field.

注释类型Column是用来指定持久化属性或字段的映射列的。

Let’s take a look at the definition:

让我们来看看这个定义。

@Target(value={METHOD,FIELD})
@Retention(value=RUNTIME)
public @interface Column {
    boolean unique;
   //other elements
 }

The unique attribute specifies whether the column is a unique key. This is a shortcut for the UniqueConstraint annotation, and is useful when the unique key constraint corresponds to only a single column.

unique属性指定了该列是否是唯一键。这是UniqueConstraint注解的一个快捷方式,当唯一键约束只对应于一个单列时,它很有用。

We’ll see how to define it in the next section.

我们将在下一节看到如何定义它。

4.2. Defining the Column Constraints

4.2.定义列的约束条件

Whenever the unique constraint is based only on one field, we can use @Column(unique=true) on that column.

当唯一约束只基于一个字段时,我们可以对该列使用@Column(unique=true)

Let’s define a unique constraint on the personNumber field:

让我们在personNumber字段上定义一个唯一约束。

@Column(unique=true)
private Long personNumber;

When we execute the schema creation process, we can validate it from the logs:

当我们执行模式创建过程时,我们可以从日志中验证它。

[main] DEBUG org.hibernate.SQL -
    alter table Person add constraint UK_d44q5lfa9xx370jv2k7tsgsqt unique (personNumber)

Similarly, if we want to restrict a Person to register with a unique email, we can add a unique constraint on the email field:

同样地,如果我们想限制一个用唯一的电子邮件进行注册,我们可以在电子邮件字段上添加一个唯一的约束条件。

@Column(unique=true)
private String email;

Let’s execute the schema creation process and check the constraints:

让我们执行模式创建过程并检查约束。

[main] DEBUG org.hibernate.SQL -
    alter table Person add constraint UK_585qcyc8qh7bg1fwgm1pj4fus unique (email)

Although this is useful when we want to put a unique constraint on a single column, sometimes we may want to add unique constraints on a composite key, which is a combination of columns. To define a composite unique key, we can use table constraints. We’ll discuss that in the next section.

尽管当我们想把唯一的约束放在一个单一的列上时,这是非常有用的,但有时我们可能想在一个复合键上添加唯一的约束,这就是一个列的组合。为了定义一个复合唯一键,我们可以使用表约束。我们将在下一节中讨论这个问题。

5. Table Constraints

5.表的限制条件

A composite unique key is a unique key made up of a combination of columns. To define a composite unique key, we can add constraints on the table instead of a column. JPA helps us achieve this using the @UniqueConstraint annotation.

复合唯一键是一个由列的组合组成的唯一键。为了定义复合唯一键,我们可以在表上添加约束,而不是列。JPA使用@UniqueConstraint注解来帮助我们实现这一目标。

5.1. @UniqueConstraint Annotation

5.1@UniqueConstraint注释

Annotation type UniqueConstraint specifies that a unique constraint is to be included in the generated DDL (Data Definition Language) for a table.

注释类型UniqueConstraint指定在生成的表的DDL(数据定义语言)中包含一个唯一约束。

Let’s take a look at the definition:

让我们来看看这个定义。

@Target(value={})
@Retention(value=RUNTIME)
public @interface UniqueConstraint {
    String name() default "";
    String[] columnNames();
}

As we can see, the name and columnNames of type String and String[], respectively, are the annotation elements that may be specified for the UniqueConstraint annotation.

我们可以看到,类型为StringString[]namecolumnNames是可以为UniqueConstraint注释指定的注释元素。

We’ll take a better look at each of the parameters in the next section, going through examples.

我们将在下一节通过实例更好地了解每个参数。

5.2. Defining Unique Constraints

5.2.定义独特的约束条件

Let’s consider our Person entity. A Person shouldn’t have any duplicate record for the active status. In other words, there won’t be any duplicate values for the key comprising personNumber and isActive. Here, we need to add unique constraints that span across multiple columns.

让我们考虑一下我们的Person实体。一个Person的活动状态不应该有任何重复的记录。换句话说,由personNumberisActive组成的键不会有任何重复的值。在这里,我们需要添加横跨多列的唯一约束。

JPA helps us achieve this with the @UniqueConstraint annotation. We use it in the @Table annotation under the uniqueConstraints attribute. Let’s remember to specify the names of the columns:

JPA通过@UniqueConstraint注解帮助我们实现这一目标。我们在uniqueConstraints属性下的@Table注解中使用它。让我们记住指定列的名称。

@Table(uniqueConstraints = { @UniqueConstraint(columnNames = { "personNumber", "isActive" }) })

We can validate it once the schema is generated:

一旦模式生成,我们就可以对其进行验证。

[main] DEBUG org.hibernate.SQL -
    alter table Person add constraint UK5e0bv5arhh7jjhsls27bmqp4a unique (personNumber, isActive)

One point to note here is that if we don’t specify a name, it’s a provider-generated value. Since JPA 2.0, we can provide a name for our unique constraint:

这里需要注意的一点是,如果我们没有指定一个名称,那么它就是一个提供者生成的值。 自JPA 2.0以来,我们可以为我们的唯一约束提供一个名称:

@Table(uniqueConstraints = { @UniqueConstraint(name = "UniqueNumberAndStatus", columnNames = { "personNumber", "isActive" }) })

And we can validate the same:

而我们也可以验证这一点。

[main] DEBUG org.hibernate.SQL -
    alter table Person add constraint UniqueNumberAndStatus unique (personNumber, isActive)

Here we added unique constraints on a set of columns. We can also add multiple unique constraints, meaning unique constraints on multiple sets of columns. We’ll do just that in the next section.

这里我们在一组列上添加了唯一约束。我们还可以添加多个唯一约束,即对多组列的唯一约束。我们将在下一节中这样做。

5.3. Multiple Unique Constraints on a Single Entity

5.3.一个实体上的多个唯一约束

A table can have multiple unique constraints. In the last section, we defined unique constraints on a composite key: personNumber and isActive status. In this section, we’ll add constraints on the combination of securityNumber and departmentCode.

一个表可以有多个唯一约束。在上一节中,我们在一个复合键上定义了唯一约束。personNumberisActive状态。在这一节中,我们将对securityNumberdepartmentCode的组合添加约束。

Let’s collect our unique indexes and specify them at once. We do this by repeating the @UniqueConstraint annotation in braces and separated by a comma:

让我们收集我们的唯一索引并一次性指定它们。我们通过重复@UniqueConstraint注解来做到这一点,注解在大括号中,用逗号分隔。

@Table(uniqueConstraints = {
   @UniqueConstraint(name = "UniqueNumberAndStatus", columnNames = {"personNumber", "isActive"}),
   @UniqueConstraint(name = "UniqueSecurityAndDepartment", columnNames = {"securityNumber", "departmentCode"})})

Now let’s see the logs, and check the constraints:

现在让我们看看日志,并检查一下约束。

[main] DEBUG org.hibernate.SQL -
    alter table Person add constraint UniqueNumberAndStatus unique (personNumber, isActive)
[main] DEBUG org.hibernate.SQL -
   alter table Person add constraint UniqueSecurityAndDepartment unique (securityNumber, departmentCode)

Up until now, we defined unique constraints on the fields in the same entity. However, in some cases, we may have referenced fields from other entities and need to ensure the uniqueness of those fields. We’ll discuss that in the next section.

到现在为止,我们对同一实体中的字段定义了唯一的约束。然而,在某些情况下,我们可能引用了其他实体的字段,需要确保这些字段的唯一性。我们将在下一节中讨论这个问题。

6. Unique Constraints on a Referenced Table Column

6.参考表列上的唯一约束条件

When we create two or more tables that are related to each other, they’re often related by a column in one table referencing the primary key of the other table. That column is called the “foreign key.” For example, the Person and Address entities are connected through the addressId field. Hence, addressId acts as a referenced table column.

当我们创建两个或多个相互关联的表时,它们通常是通过一个表中的一个列引用另一个表的主键来关联的。该列被称为 “外键”。例如,PersonAddress实体是通过addressId字段连接的。因此,addressId作为一个被引用的表列。

We can define unique constraints on the referenced columns. We’ll first implement it on a single column, and then on multiple columns.

我们可以在引用的列上定义唯一约束我们首先在单列上实现它,然后在多列上实现。

6.1. Single-Column Constraints

6.1.单列约束条件

In our Person entity, we have an address field that refers to the Address entity. A person should have a unique address.

在我们的Person实体中,我们有一个address字段,它指向Address实体。一个应该有一个唯一的地址。

So let’s define a unique constraint on the address field of the Person:

因此,让我们对Personaddress字段定义一个唯一约束。

@Column(unique = true)
private Address address;

Now let’s quickly check this constraint:

现在让我们快速检查一下这个约束条件。

[main] DEBUG org.hibernate.SQL -
   alter table Person add constraint UK_7xo3hsusabfaw1373oox9uqoe unique (address)

We can also define multiple column constraints on the referenced table column, as we’ll see in the next section.

我们还可以在引用的表列上定义多个列约束,我们将在下一节看到。

6.2. Multiple-Column Constraints

6.2.多列约束条件

We can specify unique constraints on a combination of columns. As stated earlier, we can use table constraints to do so.

我们可以在列的组合上指定唯一约束。如前所述,我们可以使用表约束来做到这一点。

Let’s define unique constraints on the personNumber and address, and add it to the uniqueConstraints array:

让我们对personNumberaddress,定义唯一约束,并将其添加到uniqueConstraints数组中。

@Entity
@Table(uniqueConstraints = 
  { //other constraints
  @UniqueConstraint(name = "UniqueNumberAndAddress", columnNames = { "personNumber", "address" })})

Finally, let’s see the unique constraints:

最后,让我们看看独特的约束。

[main] DEBUG org.hibernate.SQL -
    alter table Person add constraint UniqueNumberAndAddress unique (personNumber, address)

7. Conclusion

7.结语

The unique constraints prevent two records from having identical values in a column or set of columns.

唯一的约束条件可以防止两条记录在一列或一组列中具有相同的值。

In this article, we learned how to define unique constraints in JPA. First, we did a little recap of the unique constraints. Then we discussed the @Column(unique=true) and @UniqueConstraint annotations to define unique constraints on a single column and multiple columns, respectively.

在这篇文章中,我们学习了如何在JPA中定义唯一约束。首先,我们对唯一约束做了一个小小的回顾。然后,我们讨论了@Column(unique=true) @UniqueConstraint 注释,分别对单列和多列定义唯一约束。

As always, the examples from this article are available over on GitHub.

一如既往,本文中的示例可在GitHub上获得