一、简介
在本教程中,我们将讨论使用 JPA 和 Hibernate 定义唯一约束 。
首先,我们将探讨独特的约束以及它们与主键约束有何不同。
然后我们来看看JPA的重要注解@Column (unique=true) 和 @UniqueConstraint。 我们将实现它们来定义单列和多列的唯一约束。
最后,我们将学习如何对引用的表列定义唯一约束。
2. 独特的限制
让我们先快速回顾一下。唯一键是表中唯一标识数据库表中的记录的一组单列或多列。
唯一约束和主键约束都为一列或一组列的唯一性提供了保证。
2.1.它与主键约束有何不同?
唯一约束确保列或列组合中的数据对于每行都是唯一的。例如,表的主键充当隐式唯一约束。因此, 主键约束自动具有唯一约束。
此外,每个表只能有一个主键约束。但是,每个表可以有多个唯一约束。
简而言之,除了主键映射带来的任何约束之外,还应用唯一约束。
我们定义的唯一约束在表创建期间用于生成正确的数据库约束,也可以在运行时用于排序 insert 、 update 或 delete 语句。
2.2.什么是单列和多列约束?
唯一约束可以是列约束或表约束。在表级别,我们可以定义跨多个列的唯一约束。
JPA 允许我们使用 @Column(unique=true) 和 @UniqueConstraint 在代码中定义唯一约束。 这些注释由模式生成过程解释,自动创建约束。
首先,我们应该强调 列级约束适用于单个列,表级约束适用于整个表。
我们将在下一节中更详细地讨论这一点。
3. 设置实体
JPA 中的实体表示存储在数据库中的表。实体的每个实例代表表中的一行。
让我们首先创建一个域实体并将其映射到数据库表。对于此示例,我们将创建一个 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
}
地址 字段是来自 Address 实体的引用字段:
@Entity
@Table
public class Address implements Serializable {
@Id
@GeneratedValue
private Long id;
private String streetAddress;
//getters and setters
}
在本教程中,我们将使用此 Person 实体来演示我们的示例。
4. 列约束
当我们准备好模型后,我们就可以实现第一个唯一约束。
让我们考虑一下保存人员信息的 Person 实体。我们有 id 列的主键。该实体还保存 PersonNumber, 它不包含任何重复值。另外,我们无法定义主键,因为我们的表已经有了它。
在这种情况下,我们可以使用列唯一约束来确保在 PersonNumber 字段中不会输入重复的值。 JPA 允许我们使用带有 unique 属性的 @Column 注释来实现这一点。
在下面的部分中,我们将了解 @Column 注释,然后学习如何实现它。
4.1. @Column(唯一= true)
注释类型 Column 用于指定持久属性或字段的映射列。
我们看一下定义:
@Target(value={METHOD,FIELD})
@Retention(value=RUNTIME)
public @interface Column {
boolean unique;
//other elements
}
unique 属性指定该列是否是唯一键。这是 UniqueConstraint 注释的快捷方式,当唯一键约束仅对应于单个列时非常有用。
我们将在下一节中了解如何定义它。
4.2.定义列约束
每当唯一约束仅基于一个字段时,我们就可以对该列使用 @Column(unique=true) 。
让我们在 personNumber 字段上定义一个唯一约束:
@Column(unique=true)
private Long personNumber;
当我们执行模式创建过程时,我们可以从日志中验证它:
[main] DEBUG org.hibernate.SQL -
alter table Person add constraint UK_d44q5lfa9xx370jv2k7tsgsqt unique (personNumber)
同样,如果我们想限制一个 人 使用唯一的电子邮件注册,我们可以在 电子邮件 字段上添加唯一约束:
@Column(unique=true)
private String email;
让我们执行模式创建过程并检查约束:
[main] DEBUG org.hibernate.SQL -
alter table Person add constraint UK_585qcyc8qh7bg1fwgm1pj4fus unique (email)
虽然当我们想要对单个列施加唯一约束时这很有用,但有时我们可能想对复合键(即列的组合)添加唯一约束。要定义复合唯一键,我们可以使用表约束。我们将在下一节中讨论这个问题。
5. 表约束
复合唯一键是由列组合而成的唯一键。 要定义复合唯一键,我们可以在表而不是列上添加约束。 JPA 使用 @UniqueConstraint 注释帮助我们实现这一目标。
5.1. @UniqueConstraint 注解
注释类型 UniqueConstraint 指定将在为表生成的 DDL(数据定义语言)中包含唯一约束。
我们看一下定义:
@Target(value={})
@Retention(value=RUNTIME)
public @interface UniqueConstraint {
String name() default "";
String[] columnNames();
}
我们可以看到, * String 和 String[] 类型的 name 和 columnNames 分别是可以为 UniqueConstraint 注解指定的注解元素。 *
我们将在下一节中通过示例更好地了解每个参数。
5.2.定义唯一约束
让我们考虑一下我们的 Person 实体。一个 人 不应该有任何活动状态的重复记录。换句话说,由 personNumber 和 isActive 组成的键不会有任何重复值。在这里,我们需要添加跨多个列的唯一约束。
JPA 通过 @UniqueConstraint 注释帮助我们实现这一目标。我们在 uniqueConstraints 属性下的 @Table 注释中使用它。让我们记住指定列的名称:
@Table(uniqueConstraints = { @UniqueConstraint(columnNames = { "personNumber", "isActive" }) })
生成模式后我们可以验证它:
[main] DEBUG org.hibernate.SQL -
alter table Person add constraint UK5e0bv5arhh7jjhsls27bmqp4a unique (personNumber, isActive)
这里需要注意的一点是,如果我们不指定名称,那么它就是提供者生成的值。 从 JPA 2.0 开始,我们可以为我们的唯一约束提供一个名称:
@Table(uniqueConstraints = { @UniqueConstraint(name = "UniqueNumberAndStatus", columnNames = { "personNumber", "isActive" }) })
我们可以验证同样的结果:
[main] DEBUG org.hibernate.SQL -
alter table Person add constraint UniqueNumberAndStatus unique (personNumber, isActive)
在这里,我们对一组列添加了唯一约束。我们还可以添加多个唯一约束,这意味着对多组列的唯一约束。我们将在下一节中这样做。
5.3.单个实体上的多个唯一约束
一个表可以有多个唯一约束。 在上一节中,我们定义了组合键的唯一约束: personNumber 和 isActive 状态。在本节中,我们将添加对 securityNumber 和 DepartmentCode 组合的约束。
让我们收集我们的唯一索引并立即指定它们。我们通过在大括号中重复 @UniqueConstraint 注释并用逗号分隔来实现此目的:
@Table(uniqueConstraints = {
@UniqueConstraint(name = "UniqueNumberAndStatus", columnNames = {"personNumber", "isActive"}),
@UniqueConstraint(name = "UniqueSecurityAndDepartment", columnNames = {"securityNumber", "departmentCode"})})
现在让我们查看日志并检查约束:
[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)
到目前为止,我们对同一实体中的字段定义了唯一的约束。然而,在某些情况下,我们可能引用了其他实体的字段,需要确保这些字段的唯一性。我们将在下一节中讨论这个问题。
6. 引用表列的唯一约束
当我们创建两个或多个彼此相关的表时,它们通常通过一个表中引用另一个表的主键的列来关联。该列称为“外键”。例如, Person 和 Address 实体通过 addressId 字段连接。因此, addressId 充当引用表列。
我们可以在引用的列上定义唯一约束*。*我们将首先在单个列上实现它,然后在多个列上实现。
6.1.单列约束
在我们的 Person 实体中,我们有一个引用 Address 实体的 地址 字段。一个 人 应该有一个唯一的地址。
因此,让我们在 Person 的 地址 字段上定义一个唯一约束:
@Column(unique = true)
private Address address;
现在让我们快速检查一下这个约束:
[main] DEBUG org.hibernate.SQL -
alter table Person add constraint UK_7xo3hsusabfaw1373oox9uqoe unique (address)
我们还可以在引用的表列上定义多个列约束,我们将在下一节中看到。
6.2.多列约束
我们可以对列的组合指定唯一约束。如前所述,我们可以使用表约束来做到这一点。
让我们对 personNumber 和 地址定义唯一约束, 并将其添加到 uniqueConstraints 数组中:
@Entity
@Table(uniqueConstraints =
{ //other constraints
@UniqueConstraint(name = "UniqueNumberAndAddress", columnNames = { "personNumber", "address" })})
最后,让我们看看独特的约束:
[main] DEBUG org.hibernate.SQL -
alter table Person add constraint UniqueNumberAndAddress unique (personNumber, address)
七、结论
唯一约束可防止两个记录在一列或一组列中具有相同的值。
在本文中,我们学习了如何在 JPA 中定义唯一约束。首先,我们回顾一下独特的限制。然后我们讨论了 @Column(unique=true) 和 @UniqueConstraint 注解,分别定义单列和多列的唯一约束。
与往常一样,本文中的示例可以在 GitHub 上找到。