在本教程中,我们将讨论使用 JPA 和 Hibernate 定义唯一约束。
首先,我们将探讨唯一约束以及它们与主键约束的区别。
然后,我们将看看JPA的重要注释@Column(unique=true)和@UniqueConstraint。我们将实现它们以定义对单个列和多个列的唯一约束。
最后,我们将学习如何在引用的表列上定义唯一约束。
让我们从快速回顾开始。唯一键是表中的一组单列或多列,用于唯一标识数据库表中的记录。
唯一约束和主键约束都为一列或一组列的唯一性提供了保证。
唯一约束可确保列或列组合中的数据对于每一行都是唯一的。例如,表的主键充当隐式唯一约束。因此,主键约束自动具有唯一约束。
此外,每个表只能有一个主键约束。但是,每个表可以有多个唯一约束。
简而言之,除了主键映射所需的任何约束之外,还应用唯一约束。
我们定义的唯一约束在表创建期间用于生成适当的数据库约束,也可以在运行时用于对插入、更新或删除语句进行排序。
唯一约束可以是列约束或表约束。在表级别,我们可以跨多个列定义唯一的约束。
JPA 允许我们使用@Column(unique=true)and@UniqueConstraint在代码中定义唯一的约束。这些批注由架构生成过程解释,自动创建约束。
首先,我们应该强调列级约束适用于单个列,表级约束适用于整个表。
我们将在下一节中更详细地讨论这一点。
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
}
地址字段是地址实体中的引用字段:
@Entity
@Table
public class Address implements Serializable {
@Id
@GeneratedValue
private Long id;
private String streetAddress;
//getters and setters
}
在本教程中,我们将使用此Person实体来演示我们的示例。
准备好模型后,我们可以实现第一个唯一约束。
让我们考虑持有该人信息的Person实体。我们有一个id列的主键。此实体还保存PersonNumber,其中不包含任何重复值。此外,我们无法定义主键,因为我们的表已经有它。
在这种情况下,我们可以使用列唯一约束来确保在PersonNumber字段中没有输入重复值。JPA 允许我们使用具有唯一属性的@Column注释来实现这一点。
在以下部分中,我们将了解@Column注释,然后学习如何实现它。
批注类型Column用于指定持久性属性或字段的映射列。
我们来看看定义:
@Target(value={METHOD,FIELD})
@Retention(value=RUNTIME)
public @interface Column {
boolean unique;
//other elements
}
唯一属性指定列是否为唯一键。这是UniqueConstraint注释的快捷方式,当唯一键约束仅对应于单个列时非常有用。
我们将在下一节中看到如何定义它。
每当唯一约束仅基于一个字段时,我们就可以在该列上使用 @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)
虽然当我们想在单个列上放置唯一约束时,这很有用,但有时我们可能希望在组合键(列的组合)上添加唯一约束。要定义复合唯一键,我们可以使用表约束。我们将在下一节中讨论这一点。
复合唯一键是由列组合组成的唯一键。要定义复合唯一键,我们可以在表而不是列上添加约束。JPA 使用@UniqueConstraint注释帮助我们实现这一目标。
注释类型UniqueConstraint指定唯一约束将包含在为表生成的 DDL(数据定义语言)中。
我们来看看定义:
@Target(value={})
@Retention(value=RUNTIME)
public @interface UniqueConstraint {
String name() default "";
String[] columnNames();
}
如我们所见,String 和String[] 类型的名称和列名称分别是可以为UniqueConstraint注释指定的注释元素。
我们将在下一节中通过示例更好地查看每个参数。
让我们考虑一下我们的个人实体。人员不应有任何活动状态的重复记录。换句话说,包含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)
在这里,我们在一组列上添加了唯一的约束。我们还可以添加多个唯一约束,这意味着对多组列的唯一约束。我们将在下一节中执行此操作。
一个表可以有多个唯一约束。在上一节中,我们定义了对复合键的唯一约束:personNumber和isActive状态。在本节中,我们将添加对安全编号和部门代码组合的约束。
让我们收集我们的唯一索引并立即指定它们。我们通过在大括号中重复@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)
到目前为止,我们对同一实体中的字段定义了唯一的约束。但是,在某些情况下,我们可能引用了来自其他实体的字段,需要确保这些字段的唯一性。我们将在下一节中讨论这一点。
当我们创建两个或多个相互关联的表时,它们通常通过一个表中引用另一个表的主键的列来关联。该列称为“外键”。例如,“人员”和“地址”实体通过addressId字段进行连接。因此,地址 ID充当引用的表列。
我们可以在引用的列上定义唯一的约束。我们将首先在单个列上实现它,然后在多个列上实现它。
在我们的个人实体中,我们有一个引用地址实体的地址字段。一个人应该有一个唯一的地址。
因此,让我们在Person 的地址字段上定义一个唯一的约束:
@Column(unique = true)
private Address address;
现在让我们快速检查一下这个约束:
[main] DEBUG org.hibernate.SQL -
alter table Person add constraint UK_7xo3hsusabfaw1373oox9uqoe unique (address)
我们还可以在引用的表列上定义多个列约束,我们将在下一节中看到。
我们可以对列的组合指定唯一的约束。如前所述,我们可以使用表约束来执行此操作。
让我们定义personNumber和地址的唯一约束,并将其添加到uniqueConstraint数组中:
@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 上找到。